6 #include <evt/ShowerRecData.h>
7 #include <evt/ShowerRRecData.h>
8 #include <evt/ShowerSRecData.h>
9 #include <evt/ShowerFRecData.h>
10 #include <revt/StationRecData.h>
12 #include <evt/Event.h>
13 #include <revt/REvent.h>
14 #include <revt/Header.h>
15 #include <revt/Station.h>
16 #include <revt/Channel.h>
17 #include <evt/ShowerSimData.h>
19 #include <utl/TraceAlgorithm.h>
20 #include <utl/ErrorLogger.h>
21 #include <utl/Reader.h>
22 #include <utl/config.h>
23 #include <utl/AugerUnits.h>
24 #include <utl/MathConstants.h>
25 #include <utl/CoordinateSystemPtr.h>
26 #include <utl/StringCompare.h>
27 #include <utl/RadioGeometryUtilities.h>
28 #include <utl/PhysicalFunctions.h>
30 #include <fwk/MagneticFieldModel.h>
32 #include <det/Detector.h>
34 #include <rdet/RDetector.h>
35 #include <rdet/Station.h>
36 #include <rdet/Channel.h>
39 #include <atm/Atmosphere.h>
40 #include <atm/ProfileResult.h>
42 #include <fwk/CentralConfig.h>
44 #include <fevt/FEvent.h>
46 #include <fevt/EyeRecData.h>
58 Branch topBranch = CentralConfig::GetInstance()->
GetTopBranch(
"RdAntennaChannelToStationConverter");
62 string usedDirectionStr = topBranch.
GetChild(
"UsedDirection").
Get<
string>();
65 fUsedDirection = eRdReconstruction;
67 fUsedDirection = eSdReconstruction;
69 fUsedDirection = eFdReconstruction;
71 fUsedDirection = eMcTruth;
73 fUsedDirection = eIndividualPerStation;
75 fUsedDirection = eReference;
76 }
else if (
StringEquivalent(usedDirectionStr,
"LineOfSightStationShowerMaximum")) {
77 fUsedDirection = eLineOfSightStationShowerMaximum;
80 fDirectionOfXmax = topBranch.
GetChild(
"DirectionOfXmax").
Get<
string>();
81 fXmaxEstimator = topBranch.
GetChild(
"XmaxEstimator").
Get<
string>();
89 topBranch.
GetChild(
"rejectSaturatedStations").
GetData(fRejectSaturatedStations);
91 topBranch.
GetChild(
"calculateWeightsFromExpectedEField").
GetData(fCalculateWeightsFromExpectedEField);
92 topBranch.
GetChild(
"calculateWeightsFromAntennaPattern").
GetData(fCalculateWeightsFromAntennaPattern);
93 topBranch.
GetChild(
"useUserDefinedWeight").
GetData(fUseUserDefinedWeights);
95 if (fUseUserDefinedWeights) {
99 sstr <<
"\n\tUser defined weights for the calculation of the electric field out of 3 channel"
100 <<
" will be used, weights are:"
101 <<
" w12: " << fWeight12 <<
", w13: " << fWeight13 <<
", w23: " << fWeight23;
105 string whichEye = topBranch.
GetChild(
"UsedEye").
Get<
string>();
106 if (whichEye ==
"CO")
108 else if (whichEye ==
"HE")
110 else if (whichEye ==
"HECO")
113 ERROR(
"<UsedEye> has invalid config.");
116 sstr <<
"\n\tUse direction : " << usedDirectionStr
117 <<
"\n\tUse interpolation method : " << fInterpolationMode
118 <<
"\n\tReject saturated stations : " << fRejectSaturatedStations << endl;
121 if ((fCalculateWeightsFromAntennaPattern + fCalculateWeightsFromExpectedEField + fUseUserDefinedWeights) != 1) {
122 ERROR(
"Only one option to calculate weights must be chooses.");
135 ERROR(
"Event has no radio event!");
136 return eContinueLoop;
142 double channelfrequency = 0.;
148 pair<complex<double>, complex<double> > channel1Response;
149 pair<complex<double>, complex<double> > channel2Response;
150 V3CZero = complex<double>(0.0), complex<double>(0.0), complex<double>(0.0);
156 .GetReferenceCoordinateSystem();
164 if (!GetDirection(event, showerAxis, azimuth, zenith))
167 REvent& rEvent =
event.GetREvent();
168 const rdet::RDetector& rDetector = det::Detector::GetInstance().GetRDetector();
172 unsigned int inversionfail = 0;
174 for (
auto& station : rEvent.StationsRange()) {
180 stationspectrum[i][0] = complex<double>(0.0, 0.0);
181 stationspectrum[i][1] = complex<double>(0.0, 0.0);
182 stationspectrum[i][2] = complex<double>(0.0, 0.0);
186 vector<revt::Channel> usableChannels;
187 for (
auto& channel : station.ChannelsRange()){
188 if (channel.IsActive()) {
189 usableChannels.push_back(channel);
191 if (channel.IsSaturated()) {
192 station.SetSaturated();
194 msg <<
"detected saturated channel " << channel.GetId()
195 <<
" for station " << station.GetId() <<
".";
197 if(fRejectSaturatedStations) {
198 msg <<
" Rejecting station.";
208 if (usableChannels.size() == 0) {
210 msg <<
"Station " << station.GetId()
211 <<
" is excluded as it does not have any active channels"
212 <<
" (actually this should never happen!)";
219 if (fUsedDirection == eIndividualPerStation) {
221 if (!station.HasRecData())
222 ERROR(
"Radio station does not have RecData, but it should have by now...");
225 if (!recStation.
HasParameter(eSignalArrivalDirectionX) ||
229 msg <<
"Module is configured to use individual signal arrival directions for each station, "
230 <<
"but no direction is set for station " << station.GetId() <<
".";
237 }
else if (fUsedDirection == eLineOfSightStationShowerMaximum) {
242 if (fDirectionOfXmax ==
"MC") {
244 xMaxCore =
event.GetSimShower().GetPosition();
245 xMaxAxis = -
event.GetSimShower().GetDirection();
247 ERROR(
"Module is configured to use Monte Carlo truth direction, but event has no SimShower!");
251 if (fDirectionOfXmax ==
"Sd") {
253 ERROR(
"Module is configured to use SD direction, but event has no SRecShower!");
256 xMaxCore =
event.GetRecShower().GetSRecShower().GetCorePosition();
257 xMaxAxis =
event.GetRecShower().GetSRecShower().GetAxis();
260 else if (fDirectionOfXmax ==
"Reference") {
265 ERROR(
"The configured DirectionOfXmax was invalid.");
269 ERROR(
"The configured DirectionOfXmax was invalid.");
274 const atm::Atmosphere& theAtm = det::Detector::GetInstance().GetAtmosphere();
279 const double showerXmaxGuess = GetXmaxEstimator(event);
280 if (isnan(showerXmaxGuess) || showerXmaxGuess / (
g/
cm2) <= 1) {
282 msg <<
"Could not get xmax estimator \"" << fXmaxEstimator <<
"\": "
283 << showerXmaxGuess / (
g /
cm2);
289 const double xMaxDistance =
abs(distanceFromDepth.
Y(showerXmaxGuess));
290 const Point xMaxPos = xMaxCore + xMaxAxis * xMaxDistance;
297 const Vector lineXmaxStation = xMaxPos - stationPos;
298 azimuth = lineXmaxStation.
GetPhi(stationCS);
299 zenith = lineXmaxStation.
GetTheta(stationCS);
305 if (std::isnan(azimuth) || std::isnan(zenith)) {
307 msg <<
"Illegal azimuth / zenith: " << azimuth /
degree <<
" / " << zenith /
degree
308 <<
" deg. Check (reference) source / reconstruction.";
310 return eContinueLoop;
313 if (usableChannels.size() == 2) {
314 INFOIntermediate(
"Only two channels selected, setting weight12 to 1, the other weights to zero");
318 }
else if (usableChannels.size() == 3) {
321 if (fCalculateWeightsFromExpectedEField) {
323 event.GetRecShower().GetRRecShower().GetMagneticFieldVector();
325 showerAxis, magneticFieldAxis);
328 msg <<
"Shower axis is (" << showerAxis.
GetR(referenceCS) <<
", "
329 << showerAxis.
GetTheta(referenceCS) <<
", " << showerAxis.
GetPhi(referenceCS) <<
")";
333 msg <<
"Efield expectation is (" << efieldExpectation.
GetR(referenceCS) <<
", "
334 << efieldExpectation.
GetTheta(referenceCS) <<
", "
335 << efieldExpectation.
GetPhi(referenceCS) <<
")";
358 double weight1 = efieldExpectation * orientationChannel1;
359 double weight2 = efieldExpectation * orientationChannel2;
360 double weight3 = efieldExpectation * orientationChannel3;
362 msg <<
"weight 1 = " << weight1 <<
" weight2 = " << weight2 <<
" weight3 = " << weight3;
365 fWeight12 =
sqrt(weight1 * weight1 + weight2 * weight2);
366 fWeight13 =
sqrt(weight1 * weight1 + weight3 * weight3);
367 fWeight23 =
sqrt(weight2 * weight2 + weight3 * weight3);
370 msg <<
"using expected e-field vector to calculate weights\n"
371 <<
"\tweight12 = " << fWeight12 <<
"\n"
372 <<
"\tweight23 = " << fWeight23 <<
"\n"
373 <<
"\tweight13 = " << fWeight13 <<
"";
376 }
else if (!fUseUserDefinedWeights) {
377 ERROR(
"Calculation of weights for 3 usable channels is only supported, if "
378 "'CalculateWeightsFromExpectedEField' or 'fUseUserDefinedWeights' "
379 "is set in XML configuration.");
385 msg <<
"Station " << station.GetId()
386 <<
" does not have exactly two or three active channels! Have you forgotten"
387 <<
" to include the RdChannelSelector?";
390 "RdAntennaChannelToStationConverter does not support stations with"
391 " number of Channels != 2 or != 3.");
394 for (
int iPolarization = 0; iPolarization < 3; ++iPolarization) {
396 if (iPolarization == 0 && fWeight12 == 0) {
399 if (iPolarization == 1 && fWeight13 == 0) {
402 if (iPolarization == 2 && fWeight23 == 0) {
406 short channelId1 = 0;
407 short channelId2 = 0;
408 if (iPolarization == 0) {
411 }
else if (iPolarization == 1) {
414 }
else if (iPolarization == 2) {
419 const revt::Channel& channel1 = usableChannels.at(channelId1);
420 const revt::Channel& channel2 = usableChannels.at(channelId2);
434 if (fInfoLevel >= eInfoIntermediate) {
436 msg <<
"The 2 channels of station " << channel1.
GetStationId()
437 <<
" have different sizes, binnings or Nyquist zones!";
460 const double lowerfrequency = cDetChannel1.
GetDesignLowerFreq() / 100 * (100 - fLowSmear);
462 const double upperfrequency = cDetChannel1.
GetDesignUpperFreq() / 100 * (100 + fUpSmear);
465 const bool zenithBelowHorizon = zenith < 90. *
degree;
467 if (!zenithBelowHorizon) {
469 msg <<
"Station " << station.GetId()
470 <<
": Zenith bigger than 90 degree, will use antenna response for 89 degree.";
483 if ((!fCropFreq) || ((channelfrequency > lowerfrequency) && (channelfrequency < upperfrequency))) {
488 if (zenithBelowHorizon) {
509 sstr <<
"electric field response for " << zenith /
utl::deg <<
" , " << azimuth /
utl::deg
510 <<
", " << channelfrequency /
utl::MHz <<
"), channel1 = "
511 <<
abs(channel1Response.first) <<
", " <<
abs(channel1Response.second)
512 <<
" channel 2 = " <<
abs(channel2Response.first) <<
", "
513 <<
abs(channel2Response.second);
517 if (fCalculateWeightsFromAntennaPattern) {
518 WARNING(
"This option <calculateWeightsFromAntennaPattern> is not implemented yet.");
541 efield[0] = complex<double>(0.0, 0.0);
542 efield[1] = complex<double>(0.0, 0.0);
558 if (
abs(channel1Response.first) < fZeroLimit
559 && abs(channel1Response.second) > fZeroLimit) {
560 efield[1] = complex<double>(channel1spectrum[i] / channel1Response.second);
566 if (
abs(channel1Response.second) < fZeroLimit
567 &&
abs(channel1Response.first) > fZeroLimit) {
568 efield[0] = complex<double>(channel1spectrum[i] / channel1Response.first);
579 channel1Response.first * channel2Response.second
580 - channel1Response.second * channel2Response.first) < fZeroLimit) {
581 efield[1] = complex<double>(0.0, 0.0);
588 efield[1] = complex<double>(
589 (channel1Response.first * channel2spectrum[i]
590 - channel1spectrum[i] * channel2Response.first)
591 / (channel1Response.first * channel2Response.second
592 - channel1Response.second * channel2Response.first));
602 if (
abs(channel1Response.first) < fZeroLimit) {
603 efield[0] = complex<double>(0.0, 0.0);
610 efield[0] = complex<double>(
611 (channel1spectrum[i] / channel1Response.first)
612 - (channel1Response.second * efield[1] / channel1Response.first));
624 if (
abs(channel2Response.first) < fZeroLimit
625 &&
abs(channel2Response.second) > fZeroLimit) {
626 efield[1] = complex<double>(channel2spectrum[i] / channel2Response.second);
633 if (
abs(channel2Response.second) < fZeroLimit
634 &&
abs(channel2Response.first) > fZeroLimit) {
635 efield[0] = complex<double>(channel2spectrum[i] / channel2Response.first);
646 channel2Response.first * channel1Response.second
647 - channel2Response.second * channel1Response.first) < fZeroLimit) {
648 efield[1] = complex<double>(0.0, 0.0);
654 efield[1] = complex<double>(
655 (channel2Response.first * channel1spectrum[i]
656 - channel2spectrum[i] * channel1Response.first)
657 / (channel2Response.first * channel1Response.second
658 - channel2Response.second * channel1Response.first));
667 if (
abs(channel2Response.first) < fZeroLimit) {
668 efield[0] = complex<double>(0.0, 0.0);
674 efield[0] = complex<double>(
675 (channel2spectrum[i] / channel2Response.first)
676 - (channel2Response.second * efield[1] / channel2Response.first));
682 efield[0] = complex<double>(0.0, 0.0);
683 efield[1] = complex<double>(0.0, 0.0);
687 efield[2] = complex<double>(0.0, 0.0);
694 efield = rotateYaxis(efield, zenith);
696 efield = rotateZaxis(efield, azimuth);
700 double sumOfWeights = fWeight12 + fWeight13 + fWeight23;
701 if (iPolarization == 0) {
702 efield *= fWeight12 / sumOfWeights;
703 stationspectrum[i] += efield;
705 if (iPolarization == 1) {
706 efield *= fWeight13 / sumOfWeights;
707 stationspectrum[i] += efield;
709 if (iPolarization == 2) {
710 efield *= fWeight23 / sumOfWeights;
711 stationspectrum[i] += efield;
718 if (inversionfail != 0) {
719 if (fInfoLevel >= eInfoIntermediate) {
720 msg <<
"Linear equation solver failed for " << inversionfail <<
" frequencies!\n"
721 <<
"This is in general no problem,"
722 <<
"if the linear equation system could be solved"
723 <<
"for at least some frequencies." << endl;
745 resC[0] = complex<double>(vecC[0] * cos(angle) + vecC[2] * sin(angle));
746 resC[1] = complex<double>(vecC[1]);
747 resC[2] = complex<double>(vecC[2] * cos(angle) - vecC[0] * sin(angle));
761 resC[0] = complex<double>(vecC[0] * cos(angle) - vecC[1] * sin(angle));
762 resC[1] = complex<double>(vecC[0] * sin(angle) + vecC[1] * cos(angle));
763 resC[2] = complex<double>(vecC[2]);
775 bool RdAntennaChannelToStationConverter::GetDirection(
784 if (fUsedDirection == eReference || fUsedDirection == eSdReconstruction ||
785 fUsedDirection == eFdReconstruction || fUsedDirection == eLineOfSightStationShowerMaximum) {
791 if (fUsedDirection == eIndividualPerStation) {
796 "but individual arrival directions for each station");
797 showerAxis =
event.GetRecShower().GetRRecShower().GetAxis();
799 ERROR(
"Module is configured to use individual direction, which still take the overall "
800 " shower axis as RD direction, but event has no RRecShower!");
804 else if (fUsedDirection == eReference || fUsedDirection == eLineOfSightStationShowerMaximum) {
806 showerAxis =
event.GetRecShower().GetRRecShower().GetReferenceAxis(event);
807 azimuth = showerAxis.
GetPhi(coordinateOriginCS);
808 zenith = showerAxis.
GetTheta(coordinateOriginCS);
810 else if (fUsedDirection == eMcTruth) {
813 showerAxis = -
event.GetSimShower().GetDirection();
814 zenith = showerAxis.
GetTheta(localCS);
815 azimuth = showerAxis.
GetPhi(localCS);
817 ERROR(
"Module is configured to use Monte Carlo truth direction, but event has no SimShower!");
822 if (fUsedDirection == eSdReconstruction) {
827 ERROR(
"Module is configured to use SD direction, but event has no SRecShower!");
830 showerAxis =
event.GetRecShower().GetSRecShower().GetAxis();
831 azimuth = showerAxis.
GetPhi(coordinateOriginCS);
832 zenith = showerAxis.
GetTheta(coordinateOriginCS);
835 else if (fUsedDirection == eRdReconstruction) {
838 zenith =
event.GetRecShower().GetRRecShower().GetZenith();
839 azimuth =
event.GetRecShower().GetRRecShower().GetAzimuth();
840 showerAxis =
event.GetRecShower().GetRRecShower().GetAxis();
842 ERROR(
"Module is configured to use RD direction, but event has no RRecShower!");
846 else if (fUsedDirection == eFdReconstruction) {
851 ERROR(
"Module is configured to use FD direction, but event has no FEvent!");
854 const FEvent& fdEvent =
event.GetFEvent();
856 eyeIter != fdEvent.
EyesEnd(ComponentSelector::eHasData); ++eyeIter) {
857 if (eyeIter->GetId() != fWhichEye)
continue;
860 ERROR(
"Eye has no RecData or FRecShower but FD direction specified in the settings!");
865 azimuth = showerAxis.
GetPhi(coordinateOriginCS);
866 zenith = showerAxis.
GetTheta(coordinateOriginCS);
872 ERROR(
"No reconstructed shower found, but shower direction is required to apply antenna model! "
873 "Alternatively, individual signal arrival direction can be defined for each station, "
874 "when this feature is activated in the XML file.");
882 RdAntennaChannelToStationConverter::GetXmaxEstimator(
const evt::Event& event)
887 if (fXmaxEstimator ==
"MC") {
889 ERROR(
"Event has no sim shower but was requested.");
898 ERROR(
"Event has no SD rec shower. Can not estimate Xmax with utl::XmaxParam::Mean.");
902 const double crEnergy = sdShower.
GetEnergy();
905 if (fXmaxEstimator ==
"ParamWithSDEnergy-Sibyll2.3d")
907 else if (fXmaxEstimator ==
"ParamWithSDEnergy-EPOS-LHC")
909 else if (fXmaxEstimator ==
"ParamWithSDEnergy-QGSJETII-04")
912 ERROR(
"Wrong xml configuration!");
Branch GetTopBranch() const
double GetSignalArrivalZenith() const
returns the zenith angle of the signal arrival direction (perpendicular to wavefront) ...
Class to access station level reconstructed data.
Top of the interface to Atmosphere information.
utl::Point GetReferenceCorePosition(const Event &event) const
Returning the reference core position depending on the corresponding flag.
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
void InitSlantProfileModel(const utl::Point &core, const utl::Vector &dir, const double deltaX) const
int GetId() const
Return Id of the Channel.
double GetSignalArrivalAzimuth() const
returns the azimuth angle of the signal arrival direction (perpendicular to wavefront) ...
Detector description interface for Station-related data.
double GetDesignUpperFreq() const
Get design value of the freq-band.
Fluorescence Detector Eye Event.
Interface class to access to the SD Reconstruction of a Shower.
boost::filter_iterator< ComponentSelector, ConstAllEyeIterator > ConstEyeIterator
const evt::VGaisserHillasParameter & GetGHParameters() const
Get the Gaisser-Hillas parameters of the shower.
bool HasRecShower() const
Interface class to access to the Radio part of an event.
double GetR(const CoordinateSystemPtr &coordinateSystem) const
radius r in spherical coordinates coordinates (distance to origin)
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
ShowerRecData & GetRecShower()
Interface class to access to the RD Reconstruction of a Shower.
double GetDesignLowerFreq() const
Get design value of the freq-band.
bool HasSimShower() const
EyeIterator EyesEnd(const ComponentSelector::Status status)
double GetBinning() const
size of one slot
const atm::ProfileResult & EvaluateDistanceVsSlantDepth() const
Table of distance as a function of slant depth.
void Init()
Initialise the registry.
Detector description interface for Channel-related data.
double GetOrientationZenith() const
Get zenith-direction of Antenna for this Channel.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
int GetStationId() const
Return Id of the station to which this Channel belongs.
ShowerRRecData & GetRRecShower()
unsigned int GetNyquistZone() const
Get the Nyquist zone.
bool StringEquivalent(const std::string &a, const std::string &b, Predicate p)
Utility to compare strings for equivalence. It takes a predicate to determine the equivalence of indi...
double Y(const double x) const
Get the Y value (coordinate) for given X (ordinate)
Detector description interface for RDetector-related data.
Interface class to access Shower Simulated parameters.
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
#define INFOIntermediate(y)
Class representing a document branch.
utl::Point GetCoordinateOrigin() const
std::vector< T >::size_type SizeType
Class describing the Atmospheric profile.
Static (small and dense) vector class.
double abs(const SVector< n, T > &v)
static utl::Vector GetLorentzVector(const utl::Vector &showeraxis, const utl::Vector &vMagField)
returns the Lorentz force vector normalized to length = 1 for maximal emission (showeraxis vertical t...
bool HasRRecShower() const
bool HasFRecShower() const
Check if reconstructed shower info has been allocated.
evt::ShowerFRecData & GetFRecShower()
Reconstructed shower info for this eye.
EyeIterator EyesBegin(const ComponentSelector::Status status)
static const CSpherical kSpherical
#define WARNING(message)
Macro for logging warning messages.
void GetData(bool &b) const
Overloads of the GetData member template function.
Top of Fluorescence Detector event hierarchy.
Base class for inconsistency/illogicality exceptions.
ResultFlag
Flag returned by module methods to the RunController.
bool HasParameter(const Parameter i) const
Template class for a FADC data or calibrated data container. Use the typedefs (TraceD, TraceI, etc.) defined in Trace-fwd.h.
ChannelFrequencySpectrum & GetChannelFrequencySpectrum()
retrieve Channel Frequency Spectrum (write access, only use this if you intend to change the data) ...
utl::TraceV3C StationFrequencySpectrum
double GetFrequencyOfBin(const ChannelFrequencySpectrum::SizeType bin) const
Get the frequency corresponding to a bin of the frequency spectrum.
Class that holds the data associated to an individual radio channel.
utl::Vector GetReferenceAxis(const Event &event) const
Returning the referencedirection depending on the corresponding flag.
double Mean(const std::vector< double > &v)
utl::Point GetPosition() const
Tank position in Site Cartesian Coordinates.
static Policy::type Create(const utl::Point &theOrigin)
Create the standard local coordinate system for a Point.
std::pair< std::complex< double >, std::complex< double > > GetElectricFieldResponse(const double theta, const double phi, const double freq, std::string interpolationMode) const
#define ERROR(message)
Macro for logging error messages.
const Station & GetStation(const int stationId) const
Get station by Station Id.
bool HasSRecShower() const
double GetOrientationAzimuth() const
Get azimuth-direction of Antenna for this Channel.
fevt::EyeRecData & GetRecData()
Reconstructed data for this eye.
const utl::Vector & GetAxis() const
Shower Axis as reconstructed by the FD or FD eye.