3 #include <fwk/CentralConfig.h>
4 #include <fwk/LocalCoordinateSystem.h>
6 #include <det/Detector.h>
7 #include <rdet/RDetector.h>
10 #include <utl/FFTDataContainerAlgorithm.h>
11 #include <utl/AnalyticCoordinateTransformator.h>
12 #include <utl/TraceAlgorithm.h>
13 #include <utl/Trace.h>
15 #include <evt/Event.h>
16 #include <evt/ShowerRecData.h>
17 #include <evt/ShowerRRecData.h>
19 #include <revt/REvent.h>
20 #include <revt/Station.h>
21 #include <revt/Channel.h>
22 #include <revt/StationRecData.h>
24 #include <Minuit2/Minuit2Minimizer.h>
42 os <<
'(' << g.GetX(cs) /
meter <<
", " << g.GetY(cs) /
meter <<
", " << g.GetZ(cs) /
meter
54 topBranch.
GetChild(
"minNumberOfStations").
GetData(fMinNumberOfStations);
62 topBranch.
GetChild(
"continueAfterFailedFit").
GetData(fcontinueAfterFailedFit);
71 RdPreWaveFitter::Run(
Event& event)
75 WARNING(
"eContinueLoop: No REvent, so no reconstruction");
79 REvent& rEvent =
event.GetREvent();
85 event.MakeRecShower();
88 event.GetRecShower().MakeRRecShower();
95 fLocalCS = LocalCoordinateSystem::Create(fCoordinateOrigin);
98 err <<
"Problem when getting coordinate origin. Did you call the RdEventInitializer?"
99 <<
" Caught utl::NonExistentComponentException : " << e.
what()
100 <<
" Will Break loop";
109 ComputeSignalPosition(rEvent,
true);
111 if (fNumberOfStations < fMinNumberOfStations) {
112 INFO(
"eContinueLoop: Not enough stations.");
113 return eContinueLoop;
124 if (fcontinueAfterFailedFit) {
125 WARNING(
"PreWaveFit was not sucessful. Continuing with EField reconstruction anyway (warning: no Rd shower axis set).");
128 WARNING(
"Skipping event, because PreWaveFit was not sucessful. This default behaviour can be overwritten in XML config (be careful!).");
129 return eContinueLoop;
134 const Vector axis(1, sFitResults.
theta, sFitResults.
phi, fLocalCS, Vector::kSpherical);
140 double tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(
141 0, 0, sFitResults.
r, sFitResults.
theta, sFitResults.
phi, sFitResults.
c00, sFitResults.
c11,
142 sFitResults.
c22, sFitResults.
c01, sFitResults.
c02, sFitResults.
c12);
145 tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(1, 1,
156 tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(2, 2,
167 tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(0, 1,
178 tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(0, 2,
189 tempCov = AnalyticCoordinateTransformator::GetCartesianCovarianceFromSpherical(1, 2,
212 for (
auto& station : rEvent.StationsRange()) {
213 station.GetRecData().SetParameter(eSignalArrivalDirectionX, axis.
GetX(fLocalCS),
false);
214 station.GetRecData().SetParameter(eSignalArrivalDirectionY, axis.
GetY(fLocalCS),
false);
215 station.GetRecData().SetParameter(eSignalArrivalDirectionZ, axis.
GetZ(fLocalCS),
false);
221 info <<
"Final fit results with " << fNumberOfStations <<
" stations:"
224 <<
"\n\tChi2/NDF = " << sFitResults.
minChi <<
"/" << sFitResults.
NDF;
232 RdPreWaveFitter::Finish()
235 info <<
"PreWaveFit fit failed for " << fNFails <<
" times but continued anyway, "
236 << nSNRCut <<
" stations were rejected because of bad SNR ratio";
249 if (fNumberOfStations < 3) {
250 WARNING(
"ERROR: At least 3 Stations are needed for a plane wave fit.");
251 return eContinueLoop;
254 ROOT::Minuit2::Minuit2Minimizer* minimizer =
nullptr;
256 minimizer =
new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kMigrad);
257 }
else if (type == 1) {
258 minimizer =
new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kSimplex);
259 }
else if (type == 2) {
260 minimizer =
new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kCombined);
261 }
else if (type == 3) {
262 minimizer =
new ROOT::Minuit2::Minuit2Minimizer(ROOT::Minuit2::kScan);
265 const rdet::RDetector& rDetector = det::Detector::GetInstance().GetRDetector();
267 vector<Vector> AntennaPositions;
268 vector<double> AntennaTimes;
269 vector<double> AntennaTimesError;
272 for (
const auto& station : rEvent.CandidateStationsRange()) {
276 AntennaPositions.push_back(sPos);
278 AntennaTimes.push_back(t);
284 ChiPWF->Set(AntennaPositions, AntennaTimes, AntennaTimesError, fLocalCS);
285 minimizer->SetFunction(*ChiPWF);
288 minimizer->SetLimitedVariable(0,
"theta", fit.
theta, 0.1, 0., fThetaMax);
289 minimizer->SetVariable(1,
"phi", fit.
phi, 0.1);
292 minimizer->SetPrintLevel(0);
293 if(fInfoLevel >= 3) {
294 minimizer->SetPrintLevel(4);
296 if (!minimizer->Minimize()) {
297 fit.
status = minimizer->Status();
298 return eContinueLoop;
302 fit.
status = minimizer->Status();
305 fit.
phiError = minimizer->Errors()[1];
313 fit.
c11 = minimizer->CovMatrix(0, 0);
314 fit.
c22 = minimizer->CovMatrix(1, 1);
317 fit.
c12 = minimizer->CovMatrix(0, 1);
319 fit.
nCalls = minimizer->NCalls();
320 fit.
minChi = minimizer->MinValue();
322 fit.
NDF = fNumberOfStations - 3;
325 info <<
"fit result in mode " << type <<
": phi = " << fit.
phi /
deg <<
" theta = " << fit.
theta /
deg;
331 if (fNumberOfStations < 4) {
332 fit.
chiSquareNDF = minimizer->MinValue() / (fNumberOfStations - 2);
334 fit.
chiSquareNDF = minimizer->MinValue() / (fNumberOfStations - 3);
350 sFitParameters = sFitResults;
357 const double stepTheta = 90 / (fNInitsTheta + 1) *
degree;
358 const double stepPhi = 360 / (fNInitsPhi) *
degree;
360 double phi = -180 *
degree;
363 info <<
"Stepwidth for initial values: stepTheta = " << stepTheta /
deg
364 <<
", stepPhi = " << stepPhi /
deg;
368 bool first_fit =
true;
369 for (
int iTheta = 0; iTheta < fNInitsTheta; ++iTheta) {
370 theta = stepTheta * (iTheta + 1);
372 for (
int iPhi = 0; iPhi < fNInitsPhi; ++iPhi) {
373 phi = -180 *
degree + stepPhi * iPhi;
376 info <<
"Current start values: theta = " << theta /
deg
377 <<
" deg, phi = " << phi /
deg <<
" deg";
380 sFitParameters.
theta = theta;
381 sFitParameters.
phi = phi;
384 if (PlaneWaveFit(rEvent, sFitParameters, 1) !=
eSuccess) {
385 INFOIntermediate(
"PlaneWaveFit in kSimplex was not successful: skip to next initial value");
390 if (PlaneWaveFit(rEvent, sFitParameters, 0) !=
eSuccess) {
391 INFOIntermediate(
"PlaneWaveFit in kMigrad was not successful: skip to next initial value");
396 if (sFitParameters.
minChi < sFitResults.
minChi || first_fit) {
398 sFitResults = sFitParameters;
404 if (sFitResults.
status != 0) {
405 WARNING(
"ERROR: reconstruction was not successful");
406 return eContinueLoop;
412 if (sFitResults.
theta > TMath::Pi() / 2.) {
413 sFitParameters = sFitResults;
415 sFitParameters.
theta = TMath::Pi() - sFitParameters.
theta;
418 if (PlaneWaveFit(rEvent, sFitParameters, 1) !=
eSuccess) {
420 info <<
"Horizon Correction: PlaneWaveFit for theta = " << sFitParameters.
theta
421 <<
" in kSimplex was not successful: calling again in kMigrad mode";
426 if (PlaneWaveFit(rEvent, sFitParameters, 0) ==
eSuccess) {
429 info <<
"Horizon corrected! New theta = " << sFitParameters.
theta /
deg;
433 sFitResults = sFitParameters;
437 info <<
"Horizon Correction: PlaneWaveFit for theta "
438 << sFitParameters.
theta /
deg <<
" in kMigrad was not successful";
451 if (fNumberOfStations < 3) {
452 WARNING(
"Not enough Stations");
453 return eContinueLoop;
460 return ScanPWF(rEvent, sFitResults);
463 result = PlaneWaveFit(rEvent, sFitResults, 1);
465 WARNING(
"reuse plane wave fit in kSimplex mode was not successful");
470 result = PlaneWaveFit(rEvent, sFitResults, 0);
477 RdPreWaveFitter::ComputeRMS(
REvent& rEvent)
481 for (
auto& station : rEvent.CandidateStationsRange()) {
482 if (!station.HasRecData()) {
483 station.MakeRecData();
486 const double NoiseSearchWindowStart = station.GetRecData().GetParameter(eNoiseWindowStart);
487 const double NoiseSearchWindowStop = station.GetRecData().GetParameter(eNoiseWindowStop);
488 const double SignalSearchWindowStart = station.GetRecData().GetParameter(eSignalSearchWindowStart);
489 const double SignalSearchWindowStop = station.GetRecData().GetParameter(eSignalSearchWindowStart);
494 vector<Channel> usableChannels;
495 for (
auto& channel : station.ChannelsRange())
496 if (channel.IsActive())
497 usableChannels.push_back(channel);
500 if (usableChannels.size() == 0) {
502 info <<
"Station " << station.GetId()
503 <<
" does not have any channels, removing it! Should treat this case beforehand, e.g. in RdChannelSelector.";
509 if (usableChannels.size() != 2) {
510 if (usableChannels.size() == 3) {
512 info <<
"Station " << station.GetId()
513 <<
" does have three active channels! The PreWaveFitter does only support two active channel for the moment."
514 <<
" The first two active channels will be used.";
518 info <<
"Station " << station.GetId()
519 <<
" does not have exactly two active channels! Have you forgotten to include the RdChannelSelector?";
522 "RdPreWaveFitter does not support stations with number of Channels != 2 or != 3.");
526 const Channel& channel1 = usableChannels.at(0);
527 const Channel& channel2 = usableChannels.at(1);
529 if (fRMSonBestTrace) {
530 double RMS[2] = { 0, 0 };
531 double MaxAmp[2] = { 0, 0 };
534 for (
int i = 0; i <= 1; ++i) {
535 const Channel& channel = usableChannels.at(i);
537 const int binning = channelTrace.
GetBinning();
538 unsigned int start = NoiseSearchWindowStart / binning;
539 unsigned int stop = NoiseSearchWindowStop / binning;
540 unsigned int startSignal = SignalSearchWindowStart / binning;
541 unsigned int stopSignal = SignalSearchWindowStop / binning;
544 if (start > channelTrace.
GetSize()) {
545 WARNING(
"start of Noise Search Window is greater than the length of the trace, RMS could not be calculated");
548 info <<
"NoiseSearchWindowStop = " << stop << endl;
549 stop = min(static_cast<int>(stop), static_cast<int>(channelTrace.
GetSize()));
552 RMS[i] = TraceAlgorithm::RootMeanSquare(channelTrace, start, stop - 1);
554 MaxAmp[i] =
max(TraceAlgorithm::Max(channelTrace, startSignal, stopSignal),
555 fabs(TraceAlgorithm::Min(channelTrace, startSignal, stopSignal)));
557 info <<
"Channel " << i + 1 <<
": RMS = " << RMS[i] <<
"\tMaxAmp = " << MaxAmp[i] << endl;
560 info <<
"maxamp = " << MaxAmp[0] <<
", " << MaxAmp[1] << endl;
561 if (MaxAmp[0] > MaxAmp[1]) {
566 info <<
"RMS = " << rms << endl;
573 unsigned int start = NoiseSearchWindowStart / channelTrace1.
GetBinning();
574 unsigned int stop = NoiseSearchWindowStop / channelTrace1.
GetBinning();
576 if (start > channelTrace1.
GetSize()) {
577 if (fInfoLevel >= 1) {
579 "start of Noise Search Window is greater than the length of the trace, RMS could not be calculated");
583 info <<
"NoiseSearchWindowStart = " << start <<
"\tNoiseSearchWindowStop = " << stop
584 <<
"\tsize of channeltrace1 = " << channelTrace1.
GetSize()
585 <<
"\tsize of channeltrace2 = " << channelTrace2.
GetSize() << endl;
588 stop = min(static_cast<int>(stop), static_cast<int>(channelTrace1.
GetSize()));
591 for (
unsigned int i = start; i < stop; ++i) {
592 rms += ((channelTrace1[i] * channelTrace1[i]) + (channelTrace2[i] * channelTrace2[i]));
598 station.GetRecData().SetParameter(eNoise, rms,
false);
606 RdPreWaveFitter::ComputeSignalPosition(
REvent& rEvent,
bool hilbert)
611 for (
auto& station : rEvent.CandidateStationsRange()) {
612 if (!station.HasRecData()) {
613 station.MakeRecData();
616 double SignalSearchWindowStart = station.GetRecData().GetParameter(eSignalSearchWindowStart);
617 double SignalSearchWindowStop = station.GetRecData().GetParameter(eSignalSearchWindowStop);
619 double maxPeakTime = 0;
623 vector<Channel> usableChannels;
624 for (
auto& channel : station.ChannelsRange())
625 if (channel.IsActive())
626 usableChannels.push_back(channel);
629 if (usableChannels.size() == 0) {
631 info <<
"Station " << station.GetId()
632 <<
" does not have any channels, removing it! Should treat this case beforehand, e.g. in RdChannelSelector.";
637 if (usableChannels.size() != 2) {
638 if (usableChannels.size() == 3) {
640 info <<
"Station " << station.GetId()
641 <<
" does have three active channels! The PreWaveFitter does only support two active channel for the moment."
642 <<
" The first two active channels will be used.";
646 info <<
"Station " << station.GetId()
647 <<
" does not have exactly two active channels! Have you forgotten to include the RdChannelSelector?";
650 "RdPreWaveFitter does not support stations with number of Channels != 2 or != 3.");
654 const Channel& channel1 = usableChannels.at(0);
655 const Channel& channel2 = usableChannels.at(1);
657 if (fMaxOnComboTrace) {
664 FFTDataContainerAlgorithm::HilbertEnvelope(channelData1);
665 FFTDataContainerAlgorithm::HilbertEnvelope(channelData2);
672 const int binning = channelTrace1.
GetBinning();
673 unsigned int start = SignalSearchWindowStart / binning;
674 unsigned int stop = SignalSearchWindowStop / binning;
676 double tPeakAmplitude2 = 0.0;
677 double tPeakTime = 0.0;
678 for (
unsigned int i = start; i < stop; ++i) {
679 double amp2 =
Sqr(channelTrace1[i]) +
Sqr(channelTrace2[i]);
681 if (amp2 > tPeakAmplitude2) {
682 tPeakAmplitude2 = amp2;
683 tPeakTime = i * binning;
686 maxPeakTime = tPeakTime;
687 tMaxAmp =
sqrt(tPeakAmplitude2);
690 vector<double> peakAmplitude;
691 vector<double> peakTime;
694 for (
int i = 0; i <= 1; ++i) {
695 const Channel& channel = usableChannels.at(i);
700 FFTDataContainerAlgorithm::HilbertEnvelope(channelData);
703 const int binning = channelTrace.
GetBinning();
704 double tPeakAmplitude = 0.0;
705 double tPeakTime = 0.0;
706 unsigned int start = SignalSearchWindowStart / binning;
707 unsigned int stop = SignalSearchWindowStop / binning;
708 for (
unsigned int i = start; i < stop; ++i) {
709 if (
abs(channelTrace[i]) > tPeakAmplitude) {
710 tPeakAmplitude = channelTrace[i];
711 tPeakTime = i * binning;
714 peakAmplitude.push_back(tPeakAmplitude);
715 peakTime.push_back(tPeakTime);
718 for (
unsigned int i = 0; i < peakTime.size(); ++i) {
719 if (peakAmplitude[i] > tMaxAmp) {
720 tMaxAmp = peakAmplitude[i];
721 maxPeakTime = peakTime[i];
725 info <<
"PeakTime (ch1, ch2, maxPeakTime) = " << peakTime[0] <<
", " << peakTime[1]
726 <<
", " << maxPeakTime;
731 double traceStartTime = station.GetRecData().GetParameter(eTraceStartTime);
732 station.GetRecData().SetParameter(eSignalTime, maxPeakTime + traceStartTime,
false);
735 info <<
"setting signal time to " << maxPeakTime + traceStartTime;
740 double timeUncertainty =
sqrt(
741 station.GetRecData().GetParameterError(eTraceStartTime)
742 * station.GetRecData().GetParameterError(eTraceStartTime)
743 + binTimeError * binTimeError);
744 station.GetRecData().SetParameterError(eSignalTime, timeUncertainty,
false);
745 station.GetRecData().SetPulseFound(
true);
748 station.GetRecData().SetParameter(eSignal, tMaxAmp,
false);
752 if (!station.GetRecData().HasParameter(eNoise)) {
753 WARNING(
"RMS was not calculated. SNR can not be determined.");
755 const double rms = station.GetRecData().GetParameter(eNoise);
756 const double SNR =
Sqr(tMaxAmp) /
Sqr(rms);
757 station.GetRecData().SetParameter(eSignalToNoise, SNR,
false);
760 info <<
"rms = " << rms <<
"\t signal= " << tMaxAmp <<
"\t SNR = " << SNR;
766 info <<
"SNR condition not fulfilled, " << SNR <<
" < min SNR of " << fSNRCut <<
".";
770 station.GetRecData().SetPulseFound(
false);
777 fNumberOfStations = nStations;
ChannelFFTDataContainer & GetFFTDataContainer()
retrieve Channel FFTDataContainer (write access)
Branch GetTopBranch() const
Class to access station level reconstructed data.
void SetParameter(Parameter i, double value, bool lock=true)
double NormalizeAngleMinusPiPi(const double x)
Normalize angle to lie between -pi and pi (-180 and 180 deg)
constexpr T Sqr(const T &x)
bool HasRecShower() const
Interface class to access to the Radio part of an event.
ShowerRecData & GetRecShower()
Interface class to access to the RD Reconstruction of a Shower.
double GetParameterError(const Parameter i) const
double GetBinning() const
size of one slot
#define INFO(message)
Macro for logging informational messages.
string ToString(const G &g, const CoordinateSystemPtr cs)
void Init()
Initialise the registry.
Base class for exceptions trying to access non-existing components.
bool GetPulseFound() const
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
ChannelTimeSeries & GetChannelTimeSeries()
retrieve Channel Time Series (write access, only use this if you intend to change the data) ...
Detector description interface for RDetector-related data.
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
#define INFOIntermediate(y)
Class representing a document branch.
utl::Point GetCoordinateOrigin() const
double GetX(const CoordinateSystemPtr &coordinateSystem) const
double abs(const SVector< n, T > &v)
bool HasRRecShower() const
#define WARNING(message)
Macro for logging warning messages.
void GetData(bool &b) const
Overloads of the GetData member template function.
Base class for inconsistency/illogicality exceptions.
double GetParameter(const Parameter i) const
double GetY(const CoordinateSystemPtr &coordinateSystem) const
ResultFlag
Flag returned by module methods to the RunController.
Class that holds the data associated to an individual radio channel.
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
utl::Point GetPosition() const
Tank position in Site Cartesian Coordinates.
#define ERROR(message)
Macro for logging error messages.
const Station & GetStation(const int stationId) const
Get station by Station Id.
void SetParameterCovariance(Parameter i1, Parameter i2, double value, bool lock=true)
const char * what() const
std::exception will print this on crash