RdChannelGalacticConstantsGenerator.cc
Go to the documentation of this file.
2 #include <utl/ErrorLogger.h>
3 
4 #include <fwk/CentralConfig.h>
5 
6 #include <evt/Event.h>
7 #include <revt/REvent.h>
8 #include <revt/Header.h>
9 #include <revt/Station.h>
10 #include <revt/Channel.h>
11 #include <revt/StationRecData.h>
12 #include <revt/StationGPSData.h>
13 
14 #include <rdet/RDetector.h>
15 #include <rdet/Channel.h>
16 
17 #include <utl/Trace.h>
18 #include <utl/TraceAlgorithm.h>
19 #include <utl/Reader.h>
20 #include <utl/config.h>
21 #include <utl/AugerUnits.h>
22 #include <utl/SaveCurrentTDirectory.h>
23 
24 #include <TFile.h>
25 #include <TTree.h>
26 #include <TH2D.h>
27 #include <TProfile2D.h>
28 
29 #include <boost/scoped_ptr.hpp>
30 
31 #include <limits>
32 
33 
34 using namespace std;
35 using namespace utl;
36 using namespace fwk;
37 using namespace revt;
38 using namespace rdet;
39 
40 
42 
43 
46  {
47  INFO("RdChannelGalacticConstantsGenerator::Init()");
48 
49  Branch topBranch =
50  CentralConfig::GetInstance()->GetTopBranch("RdChannelGalacticConstantsGenerator");
51 
52  topBranch.GetChild("InfoLevel").GetData(fInfoLevel);
53  topBranch.GetChild("IgnoreStations").GetData(fIgnoreStations);
54  topBranch.GetChild("MaxIntensity").GetData(fMaxIntensity);
55  topBranch.GetChild("OutputFileName").GetData(fOutputFileName);
56  topBranch.GetChild("SaveROOTFile").GetData(fSaveROOTFile);
57  topBranch.GetChild("FileNameROOTFile").GetData(fFileNameROOTFile);
58 
59  fOutfile.open(fOutputFileName.c_str());
60 
61  return eSuccess;
62  }
63 
64 
66  RdChannelGalacticConstantsGenerator::Run(evt::Event& event)
67  {
68  INFO("RdChannelGalacticConstantsGenerator::Run()");
69 
70  REvent& rEvent = event.GetREvent();
71 
72  for (auto& station : rEvent.CandidateStationsRange()) {
73  const int stationId = station.GetId() - 100;
74  const unsigned long gpsSec = station.GetGPSData().GetSecond();
75 
76  if (gpsSec < fLowestGPSSec)
77  fLowestGPSSec = gpsSec;
78  if (gpsSec > fHighestGPSSec)
79  fHighestGPSSec = gpsSec;
80 
81  for (auto& channel : station.ChannelsRange()) {
82 
83  if (!channel.IsActive())
84  continue;
85 
86  const int channelId = channel.GetId();
87  const rdet::RDetector& rDetector = det::Detector::GetInstance().GetRDetector();
88  const rdet::Channel& detChannel = rDetector.GetStation(station.GetId()).GetChannel(channel.GetId());
89  const double lowerDesignFreq = detChannel.GetDesignLowerFreq();
90  const double upperDesignFreq = detChannel.GetDesignUpperFreq();
91 
92  const revt::ChannelFrequencySpectrum& spectrum = channel.GetChannelFrequencySpectrum();
93 
94  const int lowerBin = int(lowerDesignFreq/spectrum.GetBinning());
95  const int upperBin = int(upperDesignFreq/spectrum.GetBinning());
96  const int nSpecBins = upperBin - lowerBin;
97 
98  const double lowerFreq = channel.GetFrequencyOfBin(lowerBin + 1) / utl::MHz;
99  const double upperFreq = channel.GetFrequencyOfBin(upperBin + 1) / utl::MHz;
100 
101  const unsigned int fSpectrumSize = spectrum.GetSize();
102 
103  // calculate lst hour of current event
104  const double lst = GPSSecToLSTHourAuger(gpsSec);
105 
106  // some hard-coded binning
107  const int stationNumber = 200; // not very likely to increase in the forseeable future
108  const int lstBins = 144; // 10-minute bins, should be enough
109 
110  // first event, create TProfiles to fill data
111  if (fFirstEvent) {
112  fLSTSpecNS = new TProfile3D("LSTSpecNS", "LSTSpecNS",
113  stationNumber, 0, stationNumber,
114  lstBins, 0, 24,
115  nSpecBins, lowerFreq, upperFreq);
116  fLSTSpecEW = new TProfile3D("LSTSpecEW", "LSTSpecEW",
117  stationNumber, 0, stationNumber,
118  lstBins, 0, 24,
119  nSpecBins, lowerFreq, upperFreq);
120  fFirstEvent = false;
121  }
122 
123  double intensity = 0;
124  int intensityEntries = 0;
125 
126  if (fLSTSpecNS->GetNbinsZ() != nSpecBins) {
127  ostringstream warn;
128  warn << "Number of spectral bins (" << nSpecBins
129  << ") does not correspond to profile bins (" << fLSTSpecNS->GetNbinsZ()
130  << "). Input data probably has multiple trace lengths.";
131  WARNING(warn);
132  }
133 
134  // check if predefined normalized intensity cut is not crossed
135  for (ChannelFrequencySpectrum::SizeType i = 0; i < fSpectrumSize; ++i) {
136  const double currentFreq = channel.GetFrequencyOfBin(i) / utl::MHz;
137  if (lowerFreq <= currentFreq && currentFreq < upperFreq) {
138  intensity += abs(spectrum[i])*abs(spectrum[i]);
139  ++intensityEntries;
140  }
141  }
142  if (sqrt(intensity) / intensityEntries > fMaxIntensity) {
143  ostringstream warn;
144  warn << "Average intensity above cut, skipping this trace from station "
145  << stationId + 100 << " channel " << channelId;
146  WARNING(warn);
147  continue;
148  }
149 
150  // fill values in TProfiles
151  for (ChannelFrequencySpectrum::SizeType i = 0; i < fSpectrumSize; ++i) {
152  if (channelId == 1) {
153  const double currentFreq = channel.GetFrequencyOfBin(i) / utl::MHz;
154  if (lowerFreq <= currentFreq && currentFreq < upperFreq) {
155  fLSTSpecNS->Fill(stationId, lst, currentFreq + 0.5*spectrum.GetBinning() / utl::MHz,
156  abs(spectrum[i]));
157  }
158  }
159  if (channelId == 2) {
160  const double currentFreq = channel.GetFrequencyOfBin(i) / utl::MHz;
161  if (lowerFreq <= currentFreq && currentFreq < upperFreq) {
162  fLSTSpecEW->Fill(stationId, lst, currentFreq + 0.5*spectrum.GetBinning() / utl::MHz,
163  abs(spectrum[i]));
164  }
165  }
166  }
167  } // channel loop
168  } // station loop
169  return eSuccess;
170  }
171 
172 
174  RdChannelGalacticConstantsGenerator::Finish()
175  {
176  INFO("RdChannelGalacticConstantsGenerator::Finish()");
177 
178  // If option is selected, write profiles to root tree and file for later analysis
179  if (fSaveROOTFile) {
181  const boost::scoped_ptr<TFile> file(new TFile(fFileNameROOTFile.c_str(), "RECREATE"));
182  TTree* const tree = new TTree("fTree", "data");
183  tree->Branch("pLSTSpecNS", "TProfile3D", &fLSTSpecNS);
184  tree->Branch("pLSTSpecEW", "TProfile3D", &fLSTSpecEW);
185  tree->Branch("fLowestGPSSec", &fLowestGPSSec);
186  tree->Branch("fHighestGPSSec", &fHighestGPSSec);
187  tree->Fill();
188  tree->Write();
189  file->Close();
190  }
191 
192  // This part of the module will process the profiles and calculate the gain factors //
194 
195  // project the profile to count the number of recorded stations, and see which stations correspond to stations to be ignored
196  vector<int> vActiveStations;
197  int nIgnoreCorrection = 0;
198  const boost::scoped_ptr<TH1D> hLSTSpecNSprojX(fLSTSpecNS->ProjectionX("hLSTSpecNSprojX"));
199  std::ostringstream info;
200  info << "Active station IDs for which calibration constants will be calculated: ";
201  for (int jj = 1; jj <= hLSTSpecNSprojX->GetNbinsX(); ++jj) {
202  if (hLSTSpecNSprojX->GetBinContent(jj)) {
203  vActiveStations.push_back(jj - 1);
204  info << jj+99 << ' ';
205  for (unsigned int iignore = 0; iignore < fIgnoreStations.size(); ++iignore) {
206  if (jj-1 == fIgnoreStations[iignore]-100) {
207  ++nIgnoreCorrection;
208  info << "(ignored for average) ";
209  }
210  }
211  }
212  }
213  INFO(info);
214  info.str("");
215  const int nActiveStations = vActiveStations.size();
216 
217  // project the profile to count the number of filled LST bins
218  const int totalLSTbins = fLSTSpecNS->GetNbinsY();
219  const boost::scoped_ptr<TH2D> hLSTSpecNSprojLST((TH2D*)fLSTSpecNS->Project3D("xy"));
220  hLSTSpecNSprojLST->SetName("hLSTSpecNSprojLST");
221  for (int jj = 0; jj < nActiveStations; ++jj) {
222  int lstBins = 0;
223  for (int ybin = 1; ybin <= hLSTSpecNSprojLST->GetNbinsY(); ++ybin) {
224  const int bin = hLSTSpecNSprojLST->GetBin(ybin, vActiveStations[jj]+1);
225  if (hLSTSpecNSprojLST->GetBinContent(bin))
226  ++lstBins;
227  }
228  const double lstFraction= double(lstBins) / totalLSTbins;
229  if (lstFraction < 1) {
230  std::ostringstream warn;
231  warn << "Data from station " << vActiveStations[jj]+100
232  << " does not fully cover LST range (fraction = " << lstFraction
233  << "). This will result in a wrong calibration!";
234  WARNING(warn);
235  }
236  }
237 
238  // set band stopped bins to zero and make bins empty in profiles
239  const boost::scoped_ptr<TProfile3D> pLSTSpecNSFiltered((TProfile3D*)fLSTSpecNS->Clone());
240  delete fLSTSpecNS;
241  fLSTSpecNS = nullptr;
242  const boost::scoped_ptr<TProfile3D> pLSTSpecEWFiltered((TProfile3D*)fLSTSpecEW->Clone());
243  delete fLSTSpecEW;
244  fLSTSpecEW = nullptr;
245  pLSTSpecNSFiltered->SetName("LSTSpecNSFiltered");
246  pLSTSpecEWFiltered->SetName("LSTSpecEWFiltered");
247  for (int iz = 1; iz <= pLSTSpecNSFiltered->GetNbinsZ(); ++iz) {
248  for (int ix = 1; ix <= pLSTSpecNSFiltered->GetNbinsX(); ++ix) {
249  for (int iy = 1; iy <= pLSTSpecNSFiltered->GetNbinsY(); ++iy) {
250  const int currentbin = pLSTSpecNSFiltered->GetBin(ix, iy, iz);
251  if (pLSTSpecNSFiltered->GetBinContent(currentbin) < 1e-9) {
252  pLSTSpecNSFiltered->SetBinContent(currentbin, 0);
253  pLSTSpecNSFiltered->SetBinEntries(currentbin, 0);
254  }
255  }
256  }
257  }
258  for (int iz = 1; iz <= pLSTSpecEWFiltered->GetNbinsZ(); ++iz) {
259  for (int ix = 1; ix <= pLSTSpecEWFiltered->GetNbinsX(); ++ix) {
260  for (int iy = 1; iy <= pLSTSpecEWFiltered->GetNbinsY(); ++iy) {
261  const int currentbin = pLSTSpecEWFiltered->GetBin(ix, iy, iz);
262  if (pLSTSpecEWFiltered->GetBinContent(currentbin) < 1e-9) {
263  pLSTSpecEWFiltered->SetBinContent(currentbin, 0);
264  pLSTSpecEWFiltered->SetBinEntries(currentbin, 0);
265  }
266  }
267  }
268  }
269 
270  // clone and remove ignored stations to calculate average
271  const boost::scoped_ptr<TProfile3D> pLSTSpecNSGoodStations((TProfile3D*)pLSTSpecNSFiltered->Clone());
272  const boost::scoped_ptr<TProfile3D> pLSTSpecEWGoodStations((TProfile3D*)pLSTSpecEWFiltered->Clone());
273  pLSTSpecNSGoodStations->SetName("LSTSpecNSGoodStations");
274  pLSTSpecEWGoodStations->SetName("LSTSpecEWGoodStations");
275  for (unsigned int iignore = 0; iignore < fIgnoreStations.size(); ++iignore) {
276  for (int iz = 1; iz <= pLSTSpecNSGoodStations->GetNbinsZ(); ++iz) {
277  for (int iy = 1; iy <= pLSTSpecNSGoodStations->GetNbinsY(); ++iy) {
278  int zerobin = pLSTSpecNSGoodStations->GetBin(fIgnoreStations[iignore]-99, iy, iz);
279  pLSTSpecNSGoodStations->SetBinContent(zerobin, 0);
280  pLSTSpecNSGoodStations->SetBinEntries(zerobin, 0);
281  zerobin = pLSTSpecEWGoodStations->GetBin(fIgnoreStations[iignore]-99, iy, iz);
282  pLSTSpecEWGoodStations->SetBinContent(zerobin, 0);
283  pLSTSpecEWGoodStations->SetBinEntries(zerobin, 0);
284  }
285  }
286  }
287 
288  // create total average LST spectra by projecting along the x-axis (station axis)
289  const boost::scoped_ptr<TH2D> lstSpecNSFilteredzy((TH2D*)pLSTSpecNSGoodStations->Project3D("zy"));
290  lstSpecNSFilteredzy->SetName("LSTSpecNSFiltered_zy");
291  lstSpecNSFilteredzy->Scale(1. / (nActiveStations - nIgnoreCorrection));
292  const boost::scoped_ptr<TH2D> lstSpecEWFilteredzy((TH2D*)pLSTSpecEWGoodStations->Project3D("zy"));
293  lstSpecEWFilteredzy->SetName("LSTSpecEWFiltered_zy");
294  lstSpecEWFilteredzy->Scale(1. / (nActiveStations - nIgnoreCorrection));
295 
296  info << "The following averaged calibration constants were calculated (NS, EW):";
297 
298  ostringstream str1;
299  for (int jj = 0; jj < nActiveStations; ++jj) {
300 
301  // create complete and filtered LST spectra of individual stations
302  pLSTSpecNSFiltered->GetXaxis()->SetRange(vActiveStations[jj]+1, vActiveStations[jj]+1); // in tprofile, add one to get correct bin
303  pLSTSpecEWFiltered->GetXaxis()->SetRange(vActiveStations[jj]+1, vActiveStations[jj]+1); // set range to limit profile to one particular station
304  str1.str("");
305  str1 << "zy_stat" << vActiveStations[jj] << " ns", vActiveStations[jj];
306  // project the profile to get the spectrum of the one station in its range
307  const boost::scoped_ptr<TProfile2D> pLSTSpecNSFilteredDivided((TProfile2D*)pLSTSpecNSFiltered->Project3D(str1.str().c_str()));
308  str1.str("");
309  str1 << "zy_stat" << vActiveStations[jj] << " ew";
310  const boost::scoped_ptr<TProfile2D> pLSTSpecEWFilteredDivided((TProfile2D*)pLSTSpecEWFiltered->Project3D(str1.str().c_str()));
311  pLSTSpecNSFilteredDivided->Divide(lstSpecNSFilteredzy.get());// divide the projection by the total average lst spectrum profile (this/average)
312  pLSTSpecEWFilteredDivided->Divide(lstSpecEWFilteredzy.get());
313 
314  // now calculate divided spectra for single stations, these histograms are the frequency-dependent strengths as measured
315  const boost::scoped_ptr<TH1D> hCalibrationConstantsNS(pLSTSpecNSFilteredDivided->ProjectionY()); // project onto LST-axis
316  const boost::scoped_ptr<TH1D> hCalibrationConstantsEW(pLSTSpecEWFilteredDivided->ProjectionY());
317  hCalibrationConstantsNS->Scale(1. / totalLSTbins); // normalise to adjust for number of LST bins
318  hCalibrationConstantsEW->Scale(1. / totalLSTbins);
319 
320  // output frequency-dependent calibration constants of the stations to file
321  for (int ibin = 1; ibin <= hCalibrationConstantsNS->GetNbinsX(); ++ibin) {
322  fOutfile << vActiveStations[jj] << " 1 " << hCalibrationConstantsNS->GetBinCenter(ibin)
323  << " " << hCalibrationConstantsNS->GetBinContent(ibin) << endl;
324  }
325  for (int ibin = 1; ibin <= hCalibrationConstantsEW->GetNbinsX(); ++ibin) {
326  fOutfile << vActiveStations[jj] << " 2 " << hCalibrationConstantsEW->GetBinCenter(ibin)
327  << " " << hCalibrationConstantsEW->GetBinContent(ibin) << endl;
328  }
329 
330  // calculate and output average calibration constants for quick overview
331  info << "\n station ID " << vActiveStations[jj]+100 << ": ";
332  double averageConstantsNS = 0;
333  int constentries = 0;
334  for (int ibin = 0; ibin < hCalibrationConstantsNS->GetNbinsX(); ++ibin) {
335  if (hCalibrationConstantsNS->GetBinContent(ibin)) {
336  averageConstantsNS += hCalibrationConstantsNS->GetBinContent(ibin);
337  ++constentries;
338  }
339  }
340  averageConstantsNS /= constentries;
341  double averageConstantsEW = 0;
342  constentries = 0;
343  for (int ibin = 0; ibin < hCalibrationConstantsEW->GetNbinsX(); ++ibin) {
344  if (hCalibrationConstantsEW->GetBinContent(ibin)) {
345  averageConstantsEW += hCalibrationConstantsEW->GetBinContent(ibin);
346  ++constentries;
347  }
348  }
349  averageConstantsEW /= constentries;
350  info << '(' << averageConstantsNS << ", " << averageConstantsEW << ")";
351 
352  }
353 
354  INFO(info);
355 
356  fOutfile.close();
357 
358  return eSuccess;
359  }
360 
361 
362 #define J2000 2451545.0
363 #define Dtohr 0.066666666666666
364 #define Hrtod 15
365 
366  // function to calculate LST
367  double
368  RdChannelGalacticConstantsGenerator::GPSSecToLSTHourAuger(const int gps)
369  {
370  // FIXME DV: this code is horrible. who added this crap? this has to be removed ASAP.
371  const time_t utc = gps + 315964819 + 16; // GPS UTC offset, Leap Seconds have to be updated
372  const tm* const t = gmtime(&utc);
373  int year = t->tm_year + 1900;
374  int month = t->tm_mon + 1;
375  const int day = t->tm_mday;
376  const int hour = t->tm_hour;
377  const int min = t->tm_min;
378  const int sec = t->tm_sec;
379 
380 //#warning can you use the utl::ModifiedJulianDate here?
381  //Date to Julian Date
382  if (month <= 2) {
383  --year;
384  month += 12;
385  }
386  const int a = int(floor(year / 100.));
387  const int b = 2 - a + a/4;
388  double jd = floor(365.25*(year + 4716)) + floor(30.6001*(month + 1)) + day + b - 1524.5;
389  const double fd = double(60*60*hour + 60*min + sec) / 86400;
390  jd = jd + fd;
391 
392  static double sidereal_coeff[4] = { 280.46061837, 360.98564736629, 0.000387933, 38710000 };
393  const double dt = jd - J2000;
394  const double dt0 = dt / 36525.;
395  const double theta =
396  sidereal_coeff[0] + dt * sidereal_coeff[1] +
397  dt0 * dt0 * (sidereal_coeff[2] - dt0 / sidereal_coeff[3]); // is in degrees
398  // original J. Meeus: longitude is positive westwards *lst = mod(theta-longitude,360.) * kSTC::Dtohr;
399  // with the new convention for longitudes (positive eastwards) :
400  const double lst = fmod(theta + (360 - 69.6), 360.) * Dtohr;
401  return lst;
402  }
403 
404 }
Branch GetTopBranch() const
Definition: Branch.cc:63
double GetDesignUpperFreq() const
Get design value of the freq-band.
constexpr double MHz
Definition: AugerUnits.h:159
Interface class to access to the Radio part of an event.
Definition: REvent.h:42
double GetDesignLowerFreq() const
Get design value of the freq-band.
double GetBinning() const
size of one slot
Definition: Trace.h:138
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void Init()
Initialise the registry.
Detector description interface for Channel-related data.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
Detector description interface for RDetector-related data.
Definition: RDetector.h:46
int fd
Definition: dump1090.h:233
Class representing a document branch.
Definition: Branch.h:107
std::vector< std::complex< double > >::size_type SizeType
Definition: Trace.h:58
double abs(const SVector< n, T > &v)
SizeType GetSize() const
Definition: Trace.h:156
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
const string file
constexpr double hour
Definition: AugerUnits.h:150
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
const Station & GetStation(const int stationId) const
Get station by Station Id.
Definition: RDetector.cc:141
constexpr double day
Definition: AugerUnits.h:151
const double year
Definition: GalacticUnits.h:22

, generated on Tue Sep 26 2023.