SdTraceCalibrator.cc
Go to the documentation of this file.
1 #include "SdTraceCalibrator.h"
3 
4 #include <fwk/CentralConfig.h>
5 #include <fwk/RunController.h>
6 
7 #include <sdet/SDetector.h>
8 #include <sdet/StationTriggerAlgorithm.h>
9 
10 #include <evt/Event.h>
11 
12 #include <sevt/SEvent.h>
13 #include <sevt/EventTrigger.h>
14 #include <sevt/Station.h>
15 #include <sevt/PMT.h>
16 
17 #include <utl/Accumulator.h>
18 #include <utl/String.h>
19 
20 #define USE_SPMT_SIGNAL_AS_TOTAL 0
21 
22 
23 using namespace fwk;
24 using namespace sevt;
25 using namespace utl;
26 using namespace std;
27 
28 
29 namespace SdTraceCalibratorOG {
30 
31  // pair<> output helper
32  template<typename T1, typename T2>
33  inline
34  ostream&
35  operator<<(ostream& os, const pair<T1, T2>& p)
36  {
37  return os << '[' << p.first << ", " << p.second << ']';
38  }
39 
40 
41  inline
42  bool
43  IsInRange(const pair<double, double>& r, const double a, const double b)
44  {
45  return r.first <= r.second && a <= r.first && r.second <= b;
46  }
47 
48 
51  {
52  auto topB = CentralConfig::GetInstance()->GetTopBranch("SdTraceCalibrator");
53 
54  topB.GetChild("pmtSummationCutoff").GetData(fPMTSummationCutoff);
55  topB.GetChild("binsBeforeStartForSPMT").GetData(fBinsBeforeStartForSPMT);
56 
57  topB.GetChild("riseTimeFractions").GetData(fRiseTimeFractions);
58  topB.GetChild("fallTimeFractions").GetData(fFallTimeFractions);
59  if (!IsInRange(fRiseTimeFractions, 0, 1) || !IsInRange(fFallTimeFractions, 0, 1)) {
60  ERROR("Rise/fall time fractions must be ascending and within [0, 1]");
61  return eFailure;
62  }
63 
64  const auto testStations = topB.GetChild("testStations").Get<vector<int>>();
65  fTestStations = set<int>(testStations.begin(), testStations.end());
66 
67  fTreatHGLGEqualInSignalSearch = bool(topB.GetChild("treatHGLGEqualInSignalSearch"));
68 
69  fIncludeWaterCherenkovDetectorInScintillatorStartStopDetermination =
70  topB.GetChild("includeWaterCherenkovDetectorInScintillatorStartStopDetermination").Get<bool>();
71 
72  auto fsB = topB.GetChild("findSignal");
73  fsB.GetChild("threshold").GetData(fFindSignalThreshold);
74  fsB.GetChild("binsAboveThreshold").GetData(fFindSignalBinsAboveThreshold);
75 
76  ostringstream info;
77  info << "Parameters:\n"
78  "pmtSummationCutoff: " << fPMTSummationCutoff << "\n"
79  "binsBeforeStartForSPMT: " << fBinsBeforeStartForSPMT << "\n"
80  "riseTimeFractions: " << fRiseTimeFractions << "\n"
81  "fallTimeFractions: " << fFallTimeFractions << "\n"
82  "testStations: " << Join(" ", fTestStations) << "\n"
83  "treatHGLGEqualInSignalSearch: " << fTreatHGLGEqualInSignalSearch << "\n"
84  "includeWaterCherenkovDetectorInScintillatorStartStopDetermination: " << fIncludeWaterCherenkovDetectorInScintillatorStartStopDetermination << "\n"
85  "findSignal:\n"
86  " threshold: " << fFindSignalThreshold << "\n"
87  " binsAboveThreshold: " << fFindSignalBinsAboveThreshold;
88  INFO(info);
89 
90  return eSuccess;
91  }
92 
93 
95  SdTraceCalibrator::Run(evt::Event& event)
96  {
97  if (!event.HasSEvent())
98  return eSuccess;
99  auto& sEvent = event.GetSEvent();
100 
101  if (sEvent.StationsBegin() != sEvent.StationsEnd())
102  ++RunController::GetInstance().GetRunData().GetNamedCounters()["SdTraceCalibrator/CalibratedEvents"];
103 
104  // loop on stations
105  int nErrorZero = 0;
106  for (auto& station : sEvent.StationsRange()) {
107 
108  if (!station.HasTriggerData() ||
109  !station.HasCalibData() ||
110  !station.HasGPSData())
111  continue;
112 
113  const auto& trig = station.GetTriggerData();
114  if (trig.IsRandom() ||
115  (trig.GetErrorCode() & 0xff) || // for UUBs errorcodes are above 256.
116  station.GetCalibData().GetVersion() > 32000)
117  continue;
118 
119  // skip "bad compressed data"
120  if (sEvent.HasTrigger()) {
121  const int trigSecond = sEvent.GetTrigger().GetTime().GetGPSSecond();
122  const int timeDiff = int(station.GetGPSData().GetSecond()) - trigSecond;
123  if (abs(timeDiff) > 1)
124  continue;
125  }
126 
127  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
128  fIsUUB = dStation.IsUUB();
129 
130  // here all signal processing happens
131  if (!BuildSignals(station) ||
132  !MergeSignals(station) ||
133  !SelectSignal(station)) {
134  station.SetRejected(StationConstants::eBadCalib);
135  continue;
136  }
137 
138  ++nErrorZero;
139 
140  }
141 
142  sEvent.SetNErrorZeroStations(nErrorZero);
143 
144  return eSuccess;
145  }
146 
147 
148  int
149  SdTraceCalibrator::BuildSignals(Station& station)
150  const
151  {
152  vector<const PMT*> validPMTs;
153 
154  bool didComponents = false;
155 
156  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
157  const auto traceLength = dStation.GetFADCTraceLength();
158  const auto saturationValue = dStation.GetSaturationValue();
159 
160  for (auto& pmt : station.PMTsRange(sdet::PMTConstants::eAnyType)) {
161 
162  if (!pmt.HasCalibData() || !pmt.GetCalibData().IsTubeOk() || !pmt.HasFADCTrace())
163  continue;
164 
165  if (BuildSignals(pmt, traceLength, saturationValue) && pmt.HasRecData()) {
166 
167  if (pmt.GetType() == sdet::PMTConstants::eWaterCherenkovLarge)
168  validPMTs.push_back(&pmt); // since there are multiple such PMTs, they are processed later
169  else if (pmt.GetType() == sdet::PMTConstants::eScintillator) {
170  auto& scintillator = station.GetScintillator();
171  if (!scintillator.HasMIPTrace())
172  scintillator.MakeMIPTrace();
173  else
174  scintillator.GetMIPTrace().ResetAll();
175  auto& mipTrace = scintillator.GetMIPTrace();
176  const int traceLength = mipTrace.GetSize();
177  const auto& pmtTrace = pmt.GetRecData().GetVEMTrace();
178  for (int i = 0; i < traceLength; ++i)
179  mipTrace[i] = pmtTrace[i];
180  }
181 
182  }
183 
184  if (pmt.HasSimData() && MakeComponentVEMTraces(pmt))
185  didComponents = true;
186 
187  }
188 
189  if (!validPMTs.empty()) {
190  const int nPMTs = validPMTs.size();
191  if (!station.HasVEMTrace())
192  station.MakeVEMTrace();
193  else {
194  // clear if it exists
195  station.GetVEMTrace().ResetAll();
196  }
197  auto& vemTrace = station.GetVEMTrace();
198  const int traceLength = vemTrace.GetSize();
199  for (const auto& pmt : validPMTs) {
200  const auto& pmtTrace = pmt->GetRecData().GetVEMTrace();
201  for (int i = 0; i < traceLength; ++i)
202  vemTrace[i] += pmtTrace[i] / nPMTs;
203  }
204  }
205 
206  if (didComponents)
207  SumPMTComponents(station);
208 
209  return validPMTs.size();
210  }
211 
212 
213  bool
214  SdTraceCalibrator::BuildSignals(PMT& pmt, const unsigned int traceLength, const int saturationValue)
215  const
216  {
217  const auto& highGainTrace = pmt.GetFADCTrace(sdet::PMTConstants::eHighGain);
218 
219  // check for saturation
220  int highGainSaturatedBins = 0;
221  for (unsigned int i = 0; i < traceLength; ++i)
222  if (highGainTrace[i] >= saturationValue)
223  ++highGainSaturatedBins;
224 
225  auto& pmtRec = pmt.GetRecData();
226  pmtRec.SetFADCSaturatedBins(highGainSaturatedBins, sdet::PMTConstants::eHighGain);
227 
228  const auto& lowGainTrace = pmt.GetFADCTrace(sdet::PMTConstants::eLowGain);
229  auto& pmtCalib = pmt.GetCalibData();
230  const bool lgOK = pmtCalib.IsLowGainOk();
231  const bool isSPMT = (pmt.GetType() == sdet::PMTConstants::eWaterCherenkovSmall);
232 
233  if (lgOK) {
234  int lowGainSaturatedBins = 0;
235  for (unsigned int i = 0; i < traceLength; ++i)
236  if (lowGainTrace[i] >= saturationValue)
237  ++lowGainSaturatedBins;
238  pmtRec.SetFADCSaturatedBins(lowGainSaturatedBins, sdet::PMTConstants::eLowGain);
239 
240  const auto maxBins = CalibrationParameters::GetSaturatedBinsMaximum(fIsUUB);
241  // SmallPMT only has LowGain channel
242  if (isSPMT) {
243  if (lowGainSaturatedBins > maxBins) {
244  pmtCalib.SetIsTubeOk(false);
245  return false;
246  }
247  } else {
248  if (highGainSaturatedBins > maxBins || lowGainSaturatedBins > maxBins ||
249  (lowGainSaturatedBins && !highGainSaturatedBins)) {
250  // this is for the case where we have all or almost all of the low gain
251  // saturated and high gain saturated at the same time => no useful trace,
252  // or low gain saturated but not the high gain...
253  pmtCalib.SetIsTubeOk(false);
254  return false;
255  }
256  }
257  } else {
258  // if low gain is broken and high gain is saturated or if SPMT => no useful trace
259  if (highGainSaturatedBins || isSPMT) {
260  pmtCalib.SetIsTubeOk(false);
261  return false;
262  }
263  }
264 
265  const auto gainUsed =
266  ((highGainSaturatedBins && lgOK) || isSPMT) ? sdet::PMTConstants::eLowGain : sdet::PMTConstants::eHighGain;
267  pmtRec.SetGainUsed(gainUsed);
268 
269  if (!pmtRec.HasVEMTrace())
270  pmtRec.MakeVEMTrace();
271  auto& vemTrace = pmtRec.GetVEMTrace();
272 
273  // find signal(s)
274  auto& rawSignals = pmtRec.GetRawSignals();
275  rawSignals.clear();
276 
277  const double vemChargeFactor = pmtRec.GetVEMPeak() / pmtRec.GetVEMCharge();
278 
279  bool isTubeOK = true;
280 
281  const bool isLowGain = (gainUsed == sdet::PMTConstants::eLowGain);
282  const double gainFactor = isLowGain ? pmtRec.GetGainRatio() : 1;
283  const double gainPeakFactor = gainFactor / pmtRec.GetVEMPeak();
284 
285  if (gainPeakFactor <= 0) {
286  ostringstream err;
287  err << "PMT" << pmt.GetId() << " calibration factor nullifies the VEM trace! "
288  "Did you forget to include SdGainRatioCorrector in your module sequence?";
289  ERROR(err);
290  throw DoesNotComputeException(err.str());
291  }
292 
293  const auto& trace = isLowGain ? lowGainTrace : highGainTrace;
294  const auto& baseline = pmtRec.GetFADCBaseline(gainUsed);
295  const auto& highGainBaseline = pmtRec.GetFADCBaseline(sdet::PMTConstants::eHighGain);
296 
297  const auto findSignalThresholdMultiplier = CalibrationParameters::GetFindSignalThresholdMultiplier(fIsUUB);
298  const auto largeFADCThreshold = CalibrationParameters::GetLargeFADCThreshold(fIsUUB);
299  const auto minFADCValue = CalibrationParameters::GetMinFADCValue(fIsUUB);
300  int binsWithLargeSignal = 0;
301  int binsWithSignal = 0;
302  int binsOverThresh = 0;
303  int start = 0;
304  double max = 0;
305  double charge = 0;
306  for (int i = 0; i < int(traceLength); ++i) {
307  const int fadc = trace[i];
308  if (fadc > largeFADCThreshold)
309  ++binsWithLargeSignal;
310  const double fadcSignal = fadc - baseline[i];
311  // before the minimum FADC value was 10 and thus it might reject small signals,
312  // knowing that normal baseline fluctuations are at the level of 1-2 FADC bins,
313  // and we have new triggers with small signals it is now 4
314  if (fadcSignal > minFADCValue)
315  ++binsWithSignal;
316  const double signal = fadcSignal * gainPeakFactor;
317  vemTrace[i] = signal;
318 
319  // allways on high gain, RB: not anymore
320  const double testSignal =
321  fTreatHGLGEqualInSignalSearch ? fadcSignal : highGainTrace[i] - highGainBaseline[i];
322  if (testSignal > findSignalThresholdMultiplier * fFindSignalThreshold) {
323  // first ?
324  if (!binsOverThresh)
325  start = i;
326  ++binsOverThresh;
327  charge += signal;
328  if (signal > max)
329  max = signal;
330  } else {
331  // require at least 2 bins
332  if (binsOverThresh >= findSignalThresholdMultiplier * fFindSignalBinsAboveThreshold)
333  rawSignals.push_back(SignalSegment(start, i, binsOverThresh, charge * vemChargeFactor, max));
334  binsOverThresh = 0;
335  max = 0;
336  charge = 0;
337  }
338  }
339 
340  if (binsOverThresh >= findSignalThresholdMultiplier * fFindSignalBinsAboveThreshold) {
341  rawSignals.push_back(SignalSegment(start, traceLength, binsOverThresh, charge * vemChargeFactor, max));
342  if (binsWithLargeSignal > CalibrationParameters::GetBinsWithLargeSignalThreshold(fIsUUB) ||
343  binsWithSignal < CalibrationParameters::GetBinsWithSignalThreshold(fIsUUB))
344  isTubeOK = false;
345  }
346 
347  if (!isTubeOK && !fIsUUB) {
348  pmtCalib.SetIsTubeOk(false);
349  rawSignals.clear();
350  return false;
351  }
352 
353  auto rawIt = rawSignals.begin();
354  if (rawIt != rawSignals.end()) {
355  // joined signals
356  auto& signals = pmtRec.GetSignals();
357  signals.clear();
358  // put first in
359  signals.push_back(*rawIt);
360  const auto signalMaxDist = CalibrationParameters::GetSignalMaxDist(fIsUUB);
361  for (++rawIt; rawIt != rawSignals.end(); ++rawIt) {
362  auto& current = signals.back();
363  const int dist = rawIt->fStart - current.fStop;
364  const int maxDist = signalMaxDist + current.fBinsOverThresh;
365  // join raw signals as long they match the conditions
366  if (dist >= maxDist ||
367  (0.3*rawIt->fCharge >= current.fCharge && rawIt->fMaxValue >= 5) ||
368  !rawIt->fCharge) { // this one is probably not needed
369  signals.push_back(*rawIt);
370  } else {
371  // add bins inbetween
372  const double addCharge = accumulate(&vemTrace[current.fStop], &vemTrace[rawIt->fStart], rawIt->fCharge);
373  current.fCharge += addCharge * vemChargeFactor;
374  current.fStop = rawIt->fStop;
375  current.fBinsOverThresh += rawIt->fBinsOverThresh;
376  if (current.fMaxValue < rawIt->fMaxValue)
377  current.fMaxValue = rawIt->fMaxValue;
378  }
379  }
380  }
381 
382  return true;
383  }
384 
385 
386  bool
387  SdTraceCalibrator::MakeComponentVEMTraces(PMT& pmt)
388  const
389  {
390  auto& pmtRec = pmt.GetRecData();
391  const auto gainUsed = pmtRec.GetGainUsed();
392  const double vemFactor =
393  (gainUsed == sdet::PMTConstants::eHighGain ? 1 : pmtRec.GetGainRatio()) / pmtRec.GetVEMPeak();
394  const auto& multiFADCTrace = pmt.GetMultiFADCTrace(gainUsed);
395  if (multiFADCTrace.GetNLabels() < 2)
396  return false;
397 
398  bool didComponents = false;
399  for (const auto& component : multiFADCTrace) {
400  const auto comp =
401  static_cast<sevt::StationConstants::SignalComponent>(component.GetLabel());
402 
403  if (comp == sevt::StationConstants::eTotal)
404  continue;
405 
406  if (!pmtRec.HasVEMTrace(comp))
407  pmtRec.MakeVEMTrace(comp);
408  auto& vemTrace = pmtRec.GetVEMTrace(comp);
409 
410  // The components are taken from the double-valued traces.
411  const auto& fadcTrace = pmt.GetFADCTraceD(gainUsed, comp);
412  const int n = fadcTrace.GetSize();
413  const auto& baseline = pmtRec.GetFADCBaseline(gainUsed);
414 
415  // substract baseline from unsaturated trace
417 
418  const auto& fadcTrace = pmt.GetFADCTrace(gainUsed, comp);
419  const int n2 = fadcTrace.GetSize();
420 
421  for (int i = 0; i < n2; ++i)
422  vemTrace[i] = (fadcTrace[i] - baseline[i]) * vemFactor;
423 
424  } else {
425 
426  for (int i = 0; i < n; ++i)
427  vemTrace[i] = fadcTrace[i] * vemFactor;
428 
429  }
430 
431  didComponents = true;
432  }
433 
434  return didComponents;
435  }
436 
437 
438  void
439  SdTraceCalibrator::SumPMTComponents(Station& station)
440  const
441  {
442  // Start bin has been found and total trace and timing set. Copy individual
443  // component trace information TAP - 01/02/2006.
444 
445  vector<const TraceD*> compTrace;
446 
447  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
448 
449  for (unsigned int comp = 1; comp <= StationConstants::eLastSource; ++comp) {
450 
451  const auto component = static_cast<StationConstants::SignalComponent>(comp);
452 
453  compTrace.clear();
454 
455  // is component present?
456  for (const auto& pmt : station.PMTsRange())
457  if (pmt.HasRecData()) {
458  const auto& pmtRec = pmt.GetRecData();
459  if (pmtRec.HasVEMTrace(component))
460  compTrace.push_back(&pmtRec.GetVEMTrace(component));
461  }
462 
463  const unsigned int nPMTs = compTrace.size();
464 
465  if (nPMTs) {
466 
467  const unsigned int fadcTraceLength = dStation.GetFADCTraceLength();
468 
469  TraceD sumTrace(fadcTraceLength, dStation.GetFADCBinSize());
470 
471  for (unsigned int pos = 0; pos < fadcTraceLength; ++pos) {
472 
473  double& sum = sumTrace[pos];
474 
475  sum = 0;
476  int n = 0;
477  for (unsigned int pmtIndex = 0; pmtIndex < nPMTs; ++pmtIndex) {
478  const double value = (*compTrace[pmtIndex])[pos];
479  if (value > fPMTSummationCutoff) {
480  sum += value;
481  ++n;
482  }
483  }
484  if (n)
485  sum /= n;
486 
487  }
488 
489  if (!station.HasVEMTrace(component))
490  station.MakeVEMTrace(component);
491  station.GetVEMTrace(component) = sumTrace;
492 
493  }
494 
495  }
496  }
497 
498 
499  template<typename T1, typename T2>
500  class Interval : public pair<T1, T2> {
501  public:
502  Interval(const pair<T1, T2>& p) : pair<T1, T2>(p) { }
503 
504  bool operator<(const Interval& interval) const
505  { return this->second < interval.first; }
506 
507  bool operator==(const Interval& interval) const
508  { return interval.second > this->first && interval.first < this->second; }
509 
510  void
511  Merge(const Interval& interval)
512  {
513  if (interval.first < this->first)
514  this->first = interval.first;
515  if (interval.second > this->second)
516  this->second = interval.second;
517  }
518  };
519 
520 
521  bool
522  SdTraceCalibrator::MergeSignals(Station& station)
523  const
524  {
525  vector<PMT*> validPMTs;
526  typedef set<Interval<int, int>> Sections;
527  Sections sections;
528 
529  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
530 
531  for (auto& pmt : station.PMTsRange()) {
532 
533  if (pmt.HasCalibData() &&
534  pmt.GetCalibData().IsTubeOk() &&
535  pmt.HasRecData()) {
536 
537  validPMTs.push_back(&pmt);
538 
539  auto& signals = pmt.GetRecData().GetSignals();
540 
541  for (const auto& sig : signals) {
542 
543  Interval<int, int> newSection(make_pair(sig.fStart, sig.fStop));
544  // try to insert, then merge until insert succeeds
545  for (pair<Sections::iterator, bool> where; ; ) {
546  where = sections.insert(newSection);
547  if (!where.second) {
548  // insert failed
549  newSection.Merge(*where.first);
550  sections.erase(where.first);
551  } else
552  break;
553  }
554 
555  }
556 
557  }
558 
559  }
560 
561  const int nPMTs = validPMTs.size();
562  auto& stationSignals = station.GetSignals();
563 
564  // we have ordered set of overlapping interval unions
565  const int traceLength = dStation.GetFADCTraceLength();
566  const auto findSignalThresholdMultiplier = CalibrationParameters::GetFindSignalThresholdMultiplier(fIsUUB);
567  auto nextSectionIt = sections.begin();
568  auto currentSectionIt = nextSectionIt;
569  while (currentSectionIt != sections.end()) {
570  // add 10 bins at the end (if possible)
571  int newStop = currentSectionIt->second + 10;
572  if (newStop > traceLength)
573  newStop = traceLength;
574  ++nextSectionIt;
575  if (nextSectionIt != sections.end() && newStop > nextSectionIt->first)
576  newStop = nextSectionIt->first;
577  const int start = currentSectionIt->first;
578  // fill station signals
579  {
580  const auto& vemTrace = station.GetVEMTrace();
581  int binsOverThresh = 0;
582  double charge = 0;
583  for (const auto& pmtp : validPMTs) {
584  const auto& pmt = *pmtp;
585  const auto& pmtRec = pmt.GetRecData();
586  const auto gainUsed = pmtRec.GetGainUsed();
587 
588  const auto& trace =
589  pmt.GetFADCTrace(fTreatHGLGEqualInSignalSearch ? gainUsed : sdet::PMTConstants::eHighGain);
590  const auto& baseline =
591  pmtRec.GetFADCBaseline(fTreatHGLGEqualInSignalSearch ? gainUsed : sdet::PMTConstants::eHighGain);
592 
593  double vemSum = 0;
594  for (int i = start; i < newStop; ++i) {
595  if (trace[i] - baseline[i] >= findSignalThresholdMultiplier * fFindSignalThreshold)
596  ++binsOverThresh;
597  vemSum += vemTrace[i];
598  }
599  const double factor = pmtRec.GetVEMPeak() / pmtRec.GetVEMCharge();
600  charge += vemSum * factor;
601  }
602  stationSignals.emplace_back(start, newStop, double(binsOverThresh)/nPMTs, charge/nPMTs);
603  }
604  ++currentSectionIt;
605  }
606 
607  // Since the Scintillator only has one PMT, it's PMTRecData signals are the ScintillatorRecData
608  // Signals and no merging is necessary. Direct copying occurs from the PMTRecData
609  // SignalSegmentCollection to the ScintillatorRecData SignalSegmentCollection below.
610  if (station.HasScintillator()) {
611  const auto& pmt = station.GetScintillatorPMT();
612  if (pmt.HasRecData()) {
613  const auto& pmtSignals = station.GetScintillatorPMT().GetRecData().GetSignals();
614  auto& scintillatorSignals = station.GetScintillator().GetSignals();
615  scintillatorSignals.clear();
616  for (auto const signal : pmtSignals)
617  scintillatorSignals.push_back(signal);
618  }
619  }
620 
621  return true;
622  }
623 
624 
625  bool
626  SdTraceCalibrator::SelectSignal(Station& station)
627  const
628  {
629  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(station);
630 
631  const auto& signals = station.GetSignals();
632  const unsigned int nSignals = signals.size();
633 
634  if (!nSignals) {
635  // no signals found, check for saturation
636  // StationRecData ctor sets all other values to zero
637  for (auto& pmt : station.PMTsRange()) {
638  if (pmt.HasRecData() &&
639  pmt.HasCalibData() && pmt.GetCalibData().IsTubeOk()) {
640  const auto& pmtRec = pmt.GetRecData();
641 
642  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eLowGain))
643  station.SetLowGainSaturation();
644  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eHighGain))
645  station.SetHighGainSaturation();
646  }
647  }
648  return false;
649  }
650 
651  int maxSignalIndex = 0;
652  double maxSignal = signals[0].fCharge;
653  for (unsigned int i = 1; i < nSignals; ++i) {
654  if (maxSignal < signals[i].fCharge) {
655  maxSignalIndex = i;
656  maxSignal = signals[i].fCharge;
657  }
658  }
659 
660  const int start = signals[maxSignalIndex].fStart;
661  const int stop = signals[maxSignalIndex].fStop;
662 
663  if (!station.HasRecData())
664  station.MakeRecData();
665  auto& stRec = station.GetRecData();
666 
667  stRec.SetSignalStartSlot(start);
668  // note that end slot is (still) inclusive
669  stRec.SetSignalEndSlot(stop - 1);
670 
671  if (station.HasScintillator()) {
672 
673  int scintillatorStart = 0;
674  int scintillatorStop = 0;
675 
676  auto& scintillator = station.GetScintillator();
677  const auto& scintillatorSignals = scintillator.GetSignals();
678 
679  const int length = dStation.GetFADCTraceLength();
680 
681  if (scintillatorSignals.empty() ||
682  fIncludeWaterCherenkovDetectorInScintillatorStartStopDetermination) {
683  const double timeOffset = dStation.GetScintillatorPMT().GetTimeOffset();
684  const int traceBinOffset = floor(timeOffset / dStation.GetFADCBinSize());
685  scintillatorStart = max(0, min(start + traceBinOffset, length));
686  scintillatorStop = min(stop + traceBinOffset, length);
687  }
688 
689  if (!scintillatorSignals.empty()) {
690  // Redundant. Perhaps SignalSegmentCollection should be turned into a class
691  // with functions such as GetMaxSignal that return the SignalSegment with the
692  // maximum charge.
693  int maxIndex = 0;
694  double maxCharge = scintillatorSignals[0].fCharge;
695  for (unsigned int i = 1, n = scintillatorSignals.size(); i < n; ++i) {
696  if (maxCharge < scintillatorSignals[i].fCharge) {
697  maxIndex = i;
698  maxCharge = scintillatorSignals[i].fCharge;
699  }
700  }
701  // start/stop considering Scintillator MIP trace
702  const auto& maxSignal = scintillatorSignals[maxIndex];
703  if (scintillatorStart && scintillatorStop) {
704  scintillatorStart = max(0, min(scintillatorStart, maxSignal.fStart));
705  scintillatorStop = min(length, max(scintillatorStop, maxSignal.fStop));
706  } else {
707  scintillatorStart = max(0, maxSignal.fStart);
708  scintillatorStop = min(length, maxSignal.fStop);
709  }
710  }
711 
712  if (!scintillator.HasRecData())
713  scintillator.MakeRecData();
714  auto& scintillatorRecData = scintillator.GetRecData();
715 
716  scintillatorRecData.SetSignalStartSlot(scintillatorStart);
717  // note that stop is inclusive in offline event
718  scintillatorRecData.SetSignalEndSlot(scintillatorStop - 1);
719 
720  }
721 
722  {
723  const auto& vemTrace = station.GetVEMTrace();
724  const auto peak = for_each(&vemTrace[start+1], &vemTrace[stop], Accumulator::Max<double>(vemTrace[start]));
725  stRec.SetPeakAmplitude(peak.GetMax());
726  }
727 
728  bool highGainSaturation = false;
729  bool lowGainSaturation = false;
730  int nPMTs = 0;
731  double totalCharge = 0;
732  double spmtCharge = 0;
733  double spmtChargeErr = 0;
734 
735  Accumulator::SampleStandardDeviationN shapeStat;
736  Accumulator::SampleStandardDeviationN riseStat;
737  Accumulator::SampleStandardDeviationN fallStat;
738  Accumulator::SampleStandardDeviationN t50Stat;
739  for (auto& pmt : station.PMTsRange(sdet::PMTConstants::eAnyType)) {
740 
741  if (pmt.HasCalibData() && pmt.GetCalibData().IsTubeOk()) {
742  auto& pmtRec = pmt.GetRecData();
743 
744  if (pmt.GetType() == sdet::PMTConstants::eWaterCherenkovLarge) {
745 
746  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eHighGain))
747  highGainSaturation = true;
748  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eLowGain))
749  lowGainSaturation = true;
750 
751  const auto& vemTrace = pmtRec.GetVEMTrace();
752 
753  double charge = accumulate(&vemTrace[start], &vemTrace[stop], 0.);
754 
755  ComputeShapeRiseFallPeak(pmtRec, dStation.GetFADCBinSize(), start, start, stop, charge);
756  charge *= pmtRec.GetVEMPeak() / pmtRec.GetVEMCharge();
757  pmtRec.SetTotalCharge(charge);
758  totalCharge += charge;
759  shapeStat(pmtRec.GetShapeParameter());
760  riseStat(pmtRec.GetRiseTime());
761  fallStat(pmtRec.GetFallTime());
762  t50Stat(pmtRec.GetT50());
763  const double peak = pmtRec.GetPeakAmplitude();
764  if (peak)
765  pmtRec.SetAreaOverPeak(charge / peak);
766  ++nPMTs;
767 
768  } else if (pmt.GetType() == sdet::PMTConstants::eScintillator) {
769 
770  auto& scintillator = station.GetScintillator();
771 
772  if (!scintillator.HasMIPTrace())
773  scintillator.MakeMIPTrace();
774 
775  if (!scintillator.HasRecData())
776  scintillator.MakeRecData();
777  auto& scinRec = scintillator.GetRecData();
778 
779  const unsigned int scintillatorStart = scinRec.GetSignalStartSlot();
780  const unsigned int scintillatorStop = scinRec.GetSignalEndSlot() + 1; // stop here is exclusive
781 
782  const auto& mipTrace = scintillator.GetMIPTrace();
783 
784  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eHighGain))
785  scintillator.SetHighGainSaturation();
786  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eLowGain))
787  scintillator.SetLowGainSaturation();
788 
789  double charge = accumulate(&mipTrace[scintillatorStart], &mipTrace[scintillatorStop], 0.);
790  ComputeShapeRiseFallPeak(pmtRec, dStation.GetFADCBinSize(), scintillatorStart, scintillatorStart, scintillatorStop, charge);
791  charge *= pmtRec.GetVEMPeak() / pmtRec.GetVEMCharge();
792  pmtRec.SetTotalCharge(charge);
793  if (charge <= 0)
794  charge = 0;
795  scinRec.SetTotalSignal(charge, 0);
796  scinRec.SetRiseTime(pmtRec.GetRiseTime(), 0);
797 
798  } else if (pmt.GetType() == sdet::PMTConstants::eWaterCherenkovSmall) {
799 
800  // Add SmallPMT saturation info to sevt::Station data
801  if (pmtRec.GetFADCSaturatedBins(sdet::PMTConstants::eLowGain))
802  station.SetSmallPMTSaturation();
803 
804  double peak = 0;
805  double charge = 0;
806  const int spmtStart = max(0, start - fBinsBeforeStartForSPMT);
807 
808  if (pmtRec.HasVEMTrace()) {
809  const auto& vemTrace = pmtRec.GetVEMTrace();
810  charge = accumulate(&vemTrace[spmtStart], &vemTrace[stop], 0.);
811  ComputeShapeRiseFallPeak(pmtRec, dStation.GetFADCBinSize(), spmtStart, spmtStart, stop, charge);
812  charge *= pmtRec.GetVEMPeak() / pmtRec.GetVEMCharge();
813  peak = pmtRec.GetPeakAmplitude();
814  }
815  spmtCharge = charge;
816  spmtChargeErr = charge * pmtRec.GetVEMChargeError() / pmtRec.GetVEMCharge();
817 
818  pmtRec.SetTotalCharge(spmtCharge, spmtChargeErr);
819  if (peak>0)
820  pmtRec.SetAreaOverPeak(charge / peak);
821  }
822  }
823  }
824 
825  // this was done on the pmt vem traces due to individual pmt vem peak/charge values
826  totalCharge /= nPMTs; // only WCD large PMTs!
827  stRec.SetTotalSignal(totalCharge);
828 
829  if (highGainSaturation)
830  station.SetHighGainSaturation();
831  if (lowGainSaturation) {
832  station.SetLowGainSaturation();
833 #if USE_SPMT_SIGNAL_AS_TOTAL
834  // if LPMTs LowGain is saturated, use SmallPMT signal
835  if (fIsUUB && station.HasSmallPMT() &&
836  station.IsSmallPMTOk()) {
837  if (spmtCharge>0 && spmtChargeErr>0)
838  stRec.SetTotalSignal(spmtCharge, spmtChargeErr);
839  else {
840  ostringstream warn;
841  warn << "Station " << station.GetId() << ": zero SmallPMT signal after successful calibration!";
842  WARNING(warn);
843  station.SetIsSmallPMTOk(false);
844  }
845  }
846 #endif
847  }
848 
849  if (totalCharge <= 0)
850  return false;
851 
852  if (nPMTs < 2) {
853  stRec.SetShapeParameter(shapeStat.GetAverage(nPMTs), 0);
854  stRec.SetRiseTime(riseStat.GetAverage(nPMTs), 0);
855  stRec.SetFallTime(fallStat.GetAverage(nPMTs), 0);
856  stRec.SetT50(t50Stat.GetAverage(nPMTs), 0);
857  } else {
858  stRec.SetShapeParameter(shapeStat.GetAverage(nPMTs),
859  shapeStat.GetStandardDeviation(nPMTs));
860  stRec.SetRiseTime(riseStat.GetAverage(nPMTs),
861  riseStat.GetStandardDeviation(nPMTs));
862  stRec.SetFallTime(fallStat.GetAverage(nPMTs),
863  fallStat.GetStandardDeviation(nPMTs));
864  stRec.SetT50(t50Stat.GetAverage(nPMTs),
865  t50Stat.GetStandardDeviation(nPMTs));
866  }
867 
868  const auto& gpsData = station.GetGPSData();
869 
870  // timing of the trace END
871  const TimeStamp gpsTime(gpsData.GetSecond(), gpsData.GetCorrectedNanosecond());
872 
873  const double fadcBinSize = dStation.GetFADCBinSize();
874 
875  const TimeInterval pldTimeOffset = station.GetTriggerData().GetPLDTimeOffset();
876 
877  // timing of the trace BEGINNING
878  const TimeStamp traceTime = gpsTime + pldTimeOffset -
879  TimeInterval(dStation.GetFADCTraceLength() * fadcBinSize);
880  station.SetTraceStartTime(traceTime);
881 
882  // timing of the SIGNAL START
883  const TimeStamp signalTime = traceTime + TimeInterval((start - 0.5) * fadcBinSize);
884  stRec.SetSignalStartTime(signalTime);
885 
886  // timing of scintillator
887  if (station.HasScintillator()) {
888  auto& scintillator = station.GetScintillator();
889  if (scintillator.HasRecData()) {
890  auto& scinRec = scintillator.GetRecData();
891  const TimeStamp scinSignalTime = traceTime + TimeInterval((scinRec.GetSignalStartSlot() - 0.5) * fadcBinSize);
892  scinRec.SetSignalStartTime(scinSignalTime);
893  }
894  }
895 
896  return true;
897  }
898 
899 
900  // set rise/fall time for PMT trace and return shape parameter
901  void
902  SdTraceCalibrator::ComputeShapeRiseFallPeak(PMTRecData& pmtRec,
903  const double binTiming,
904  const unsigned int startBin,
905  const unsigned int startIntegration,
906  const unsigned int endIntegration, // end is exclusive
907  const double traceIntegral)
908  const
909  {
910  // sorry for not using the nice TraceAlgorithms, but all this values can
911  // be calculated in single trace pass
912 
913  if (traceIntegral <= 0)
914  return;
915 
916  const double riseStartSentry = fRiseTimeFractions.first * traceIntegral;
917  const double riseEndSentry = fRiseTimeFractions.second * traceIntegral;
918  const double fallStartSentry = fFallTimeFractions.first * traceIntegral;
919  const double fallEndSentry = fFallTimeFractions.second * traceIntegral;
920  const unsigned int shapeSentry =
921  startIntegration + (unsigned int)(600*nanosecond / binTiming);
922  const double t50Sentry = 0.5 * traceIntegral;
923  double riseStartBin = 0;
924  double riseEndBin = 0;
925  double fallStartBin = 0;
926  double fallEndBin = 0;
927  double t50Bin = 0;
928  double sumEarly = 0;
929 
930  double peakAmplitude = 0;
931  double runningSum = 0;
932  double oldSum = 0;
933 
934  const auto& trace = pmtRec.GetVEMTrace();
935 
936  for (unsigned int i = startIntegration; i < endIntegration; ++i) {
937 
938  const double binValue = trace[i];
939  runningSum += binValue;
940 
941  if (peakAmplitude < binValue)
942  peakAmplitude = binValue;
943 
944  if (!sumEarly && i >= shapeSentry)
945  sumEarly = oldSum;
946 
947  if (!riseStartBin && runningSum > riseStartSentry)
948  riseStartBin = i - (runningSum - riseStartSentry) / (runningSum - oldSum);
949 
950  if (!riseEndBin && runningSum > riseEndSentry)
951  riseEndBin = i - (runningSum - riseEndSentry) / (runningSum - oldSum);
952 
953  if (!fallStartBin && runningSum > fallStartSentry)
954  fallStartBin = i - (runningSum - fallStartSentry) / (runningSum - oldSum);
955 
956  if (!fallEndBin && runningSum > fallEndSentry)
957  fallEndBin = i - (runningSum - fallEndSentry) / (runningSum - oldSum);
958 
959  if (!t50Bin && runningSum > t50Sentry)
960  t50Bin = i - (runningSum - t50Sentry) / (runningSum - oldSum);
961 
962  oldSum = runningSum;
963 
964  }
965 
966  pmtRec.SetPeakAmplitude(peakAmplitude);
967  pmtRec.SetRiseTime(binTiming * (riseEndBin-riseStartBin), 0);
968  pmtRec.SetFallTime(binTiming * (fallEndBin-fallStartBin), 0);
969  pmtRec.SetT50(binTiming * (t50Bin-startBin));
970  if (shapeSentry < endIntegration) {
971  const double sumLate = runningSum - sumEarly;
972  if (sumLate > 1e-3)
973  pmtRec.SetShapeParameter(sumEarly / sumLate);
974  }
975  }
976 
977 }
utl::TraceD & GetVEMTrace(const StationConstants::SignalComponent source=StationConstants::eTotal)
Traces calibrated in VEM Peak.
Definition: PMTRecData.h:46
int GetId() const
Get the station Id.
class to hold data at PMT level
Definition: SEvent/PMT.h:28
total (shower and background)
void SetSignalStartSlot(const unsigned int slot)
Start time of the signal in time slots from beginning of trace.
PMTCalibData & GetCalibData()
Get object containing PMT calibration data.
Definition: SEvent/PMT.h:56
sdet::PMTConstants::PMTType GetType() const
Definition: SEvent/PMT.h:35
void SetShapeParameter(const double shape)
Definition: PMTRecData.h:207
PMTRecData & GetRecData()
Get object containing PMT reconstructed data.
Definition: SEvent/PMT.h:48
SignalSegmentCollection & GetSignals()
void SetFallTime(const double fallTime, const double rms)
Definition: PMTRecData.h:177
sevt::StationRecData & GetRecData()
Get station level reconstructed data.
ScintillatorRecData & GetRecData()
Get object containing scintillator reconstructed data.
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void SetTraceStartTime(const utl::TimeStamp &Time)
Set absolute start time of the VEM trace.
void Init()
Initialise the registry.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
void Merge(const Interval &interval)
unsigned int GetId() const
Return Id of the PMT.
Definition: SEvent/PMT.h:32
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
utl::TraceD & GetVEMTrace(const StationConstants::SignalComponent source=StationConstants::eTotal)
signal trace calibrated in [VEM charge]
void SetPeakAmplitude(const double peak)
Definition: PMTRecData.h:206
oss<< "0b";oss<< ((x >> i)&1);return oss.str();}template< class S, class V > std::string Join(const S &sep, const V &v)
Definition: String.h:60
void SetFADCSaturatedBins(const int num, const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain)
Definition: PMTRecData.h:220
#define max(a, b)
class to hold data at Station level
void SetLowGainSaturation(const bool sat=true)
total FADC trace, with no saturation applied by FADC/baseline simulator
bool operator==(const Interval &interval) const
class to hold reconstructed data at PMT level
Definition: PMTRecData.h:38
bool operator<(const Interval &interval) const
constexpr double nanosecond
Definition: AugerUnits.h:143
double abs(const SVector< n, T > &v)
const double second
Definition: GalacticUnits.h:32
void MakeVEMTrace(const StationConstants::SignalComponent source=StationConstants::eTotal)
Make a VEM trace object.
sevt::StationGPSData & GetGPSData()
Get GPS data for the station.
bool HasVEMTrace(const StationConstants::SignalComponent source=StationConstants::eTotal) const
Check whether VEM trace exists.
utl::TraceD & GetFADCTraceD(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain, const StationConstants::SignalComponent source=StationConstants::eTotal)
Definition: SEvent/PMT.h:121
SizeType GetSize() const
Definition: Trace.h:156
Scintillator & GetScintillator()
#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
Holds information characterizing portions of traces with signals.
Definition: SignalSegment.h:17
Base class for inconsistency/illogicality exceptions.
utl::TraceI & GetFADCTrace(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain, const StationConstants::SignalComponent source=StationConstants::eTotal)
Definition: SEvent/PMT.h:72
bool IsLowGainOk() const
Definition: PMTCalibData.h:31
const utl::MultiTraceI & GetMultiFADCTrace(const sdet::PMTConstants::PMTGain gain=sdet::PMTConstants::eHighGain) const
Definition: SEvent/PMT.h:86
void MakeRecData()
Make station reconstructed data object.
void ResetAll(const T &value=T())
Definition: Trace.h:160
void MakeMIPTrace(const StationConstants::SignalComponent source=StationConstants::eTotal)
Make a VEM trace object.
Interval(const pair< T1, T2 > &p)
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
sdet::PMTConstants::PMTGain GetGainUsed() const
Definition: PMTRecData.h:164
bool HasRecData() const
Check whether station reconstructed data exists.
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
bool HasScintillator() const
void SetT50(const double t50)
Definition: PMTRecData.h:183
void SetSmallPMTSaturation(const bool sat=true)
bool IsInRange(const double x, const vector< double > &r)
sevt::StationTriggerData & GetTriggerData()
Get Trigger data for the station.
void SetRiseTime(const double riseTime, const double rms)
Definition: PMTRecData.h:172
SignalSegmentCollection & GetSignals()
void SetHighGainSaturation(const bool sat=true)
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
bool HasSEvent() const
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)

, generated on Tue Sep 26 2023.