SdEventSelector.cc
Go to the documentation of this file.
1 #include "SdEventSelector.h"
2 
3 #include <fwk/CentralConfig.h>
4 #include <fwk/RunController.h>
5 
6 #include <det/Detector.h>
7 
8 #include <sdet/SDetector.h>
9 #include <sdet/Station.h>
10 
11 #include <evt/Event.h>
12 #include <evt/ShowerRecData.h>
13 #include <evt/ShowerSRecData.h>
14 
15 #include <sevt/SEvent.h>
16 #include <sevt/Header.h>
17 #include <sevt/EventTrigger.h>
18 #include <sevt/Station.h>
19 #include <sevt/StationTriggerData.h>
20 #include <sevt/StationSimData.h>
21 #include <sevt/StationRecData.h>
22 #include <sevt/PMT.h>
23 #include <sevt/PMTRecData.h>
24 #include <sevt/PMTCalibData.h>
25 #include <sevt/IsLightning.h>
26 
27 #include <utl/Vector.h>
28 #include <utl/AxialVector.h>
29 #include <utl/GeometryUtilities.h>
30 #include <utl/PhysicalConstants.h>
31 #include <utl/ErrorLogger.h>
32 #include <utl/String.h>
33 #include <utl/Reader.h>
34 #include <utl/TabularStream.h>
35 
36 #include <TMinuit.h>
37 
38 #include <boost/range/iterator_range.hpp>
39 
40 #include <set>
41 
42 using namespace fwk;
43 using namespace evt;
44 using namespace sevt;
45 using namespace utl;
46 using namespace std;
47 using namespace SdEventSelectorOG;
48 using boost::make_iterator_range;
49 
50 
51 // globals
52 
53 namespace SdEventSelectorOG {
54 
55  /*
56  In triangular grid distances grow as following
57 
58  1500 m
59  shell fac array
60  0 0 0
61  1 1 1500 C1
62  2 1.73205 2598 hexagon skew diagonal
63  3 2 3000 hexagon diameter
64  4 2.64575 3969
65  5 3 4500
66  6 3.46410 5196
67  7 3.60555 5408
68  */
69 
70  //inlines
71 
72  // stl helpers
73  template<typename Iterator>
74  inline
75  Iterator
76  Next(Iterator it)
77  {
78  return ++it;
79  }
80 
81 
82  // distance helper
83  inline
84  double
85  Distance(const sdet::Station& i, const sdet::Station& j)
86  {
87  return (i.GetPosition() - j.GetPosition()).GetMag();
88  }
89 
90 
91  inline
92  bool
93  IsInRange(const double x, const vector<double>& r)
94  {
95  return (r[0] < x && x < r[1]);
96  }
97 
98 
99  namespace SeedFit {
100 
103  double gTimeI;
104  double gTimeJ;
105 
106  void
107  Chi2(int& /*nPar*/, double* const /*grad*/, double& value,
108  double* const par, const int /*flag*/)
109  {
110  const double& phi = par[0];
111 
112  const double u = cos(phi);
113  const double v = sin(phi);
114 
115  value =
116  Sqr(u - gTimeI) +
118  }
119 
120  } // namespace SeedFit
121 
122 
125  {
126  if (!event.HasRecShower())
127  event.MakeRecShower();
128  auto& shRec = event.GetRecShower();
129  if (!shRec.HasSRecShower())
130  shRec.MakeSRecShower();
131  return shRec.GetSRecShower();
132  }
133 
134 
135  void
136  MakeInfo(const vector<int>& ids, const string& message)
137  {
138  if (ids.empty())
139  return;
140  ostringstream info;
141  info << "station" << String::Plural(ids) << ' ' << String::OfSortedIds(ids) << ' ' << message;
142  INFO(info);
143  }
144 
145 
146  inline
147  double
148  SdEventSelector::CTimeDifferenceMargin(const Station& i, const Station& j)
149  const
150  {
152  j.GetRecData().GetSignalStartTime()).GetInterval()) -
153  fLightCompatibilityTolerance);
154  }
155 
156 
157  int
158  SdEventSelector::StationSelection(sevt::SEvent& sEvent)
159  const
160  {
161  vector<int> ssElectronicsType;
162  vector<int> ssOffGrid;
163  vector<int> ssDense;
164  vector<int> ssLightning;
165  vector<int> ssNoRecData;
166  vector<int> ssTOTd;
167  vector<int> ssMoPS;
168 
169  int nCandidates = 0;
170  for (auto& s : sEvent.StationsRange()) {
171  const int sId = s.GetId();
172  const auto& dStation = det::Detector::GetInstance().GetSDetector().GetStation(s);
173 
174  if (fRejectUBStations && !s.IsUUB()) {
175  ssElectronicsType.push_back(sId);
177  }
178 
179  if (fRejectUUBStations && s.IsUUB()) {
180  ssElectronicsType.push_back(sId);
182  }
183 
184  if (!dStation.IsInGrid(sdet::SDetectorConstants::GridIndex(fGridType))) {
185  ssOffGrid.push_back(sId);
186  s.SetRejected(StationConstants::eOffGrid);
187  }
188 
189  if (dStation.IsDense()) {
190  ssDense.push_back(sId);
191  s.SetRejected(StationConstants::eDenseArray);
192  }
193 
194  if (s.IsCandidate()) {
195 
196  if (!s.IsUUB()) {
197 
198  /* For now we skip upgraded stations
199  Stations with new electronics are wrongly flagged as lightning
200  as the algorithm does not handle properly new traces (higher sampling rate and resolution in amplitude)
201  TODO: update Lightning algorithm for UUB
202  */
203 
204  if (IsLightning(s)) {
205  ssLightning.push_back(sId);
206  switch (fRejectLightning) {
207  case 1:
208  // flag station
209  s.SetRejected(StationConstants::eLightning);
210  break;
211  case 2:
212  // reject whole event
213  WARNING("Lightning detected, whole event rejected.");
214  return 0;
215  }
216  }
217  }
218 
219  if (!s.HasRecData()) {
220  ssNoRecData.push_back(sId);
221  s.SetRejected(StationConstants::eNoRecData);
222  }
223 
224  const auto& sTrig = s.GetTriggerData();
225  const bool thtot = sTrig.IsThresholdOrTimeOverThreshold(); // old triggers
226 
227  if (!thtot) {
228  const bool totd = sTrig.IsTimeOverThresholdDeconvoluted();
229  const bool silenceTotd = fSilenceTOTdStations && totd;
230  const bool mops = sTrig.IsMultiplicityOfPositiveSteps();
231  const bool silenceMops = fSilenceMoPSStations && mops;
232  if ((fSilenceTOTdStations && silenceMops) || (silenceTotd && !mops) || (silenceMops && !totd)) {
233  if (!s.IsRejected())
234  s.SetSilent();
235  if (totd)
236  ssTOTd.push_back(sId);
237  if (mops)
238  ssMoPS.push_back(sId);
239  }
240  }
241 
242  ++nCandidates;
243 
244  }
245  }
246 
247  MakeInfo(ssOffGrid, "rejected as off-grid.");
248  MakeInfo(ssDense, "rejected as dense.");
249  MakeInfo(ssLightning, fRejectLightning ? "rejected as potential lightning." : "NOT rejected as lightning.");
250  MakeInfo(ssElectronicsType, "rejected due to electronics type");
251  MakeInfo(ssNoRecData, "without RecData rejected.");
252  MakeInfo(ssTOTd, "set silent because only TOTd.");
253  MakeInfo(ssMoPS, "set silent because only MoPS.");
254 
255  return nCandidates;
256  }
257 
258 
259  string
260  GetT4TriggerName(const bool isT4,
261  const bool isFD,
262  const bool is3TOT,
263  const bool is3TOTd,
264  const bool is3MoPS,
265  const bool is3TOTMix,
266  const bool is4C1)
267  {
268  ostringstream trig;
269  if (isT4) {
270  if (isFD)
271  trig << "FD";
272  if (is3TOT)
273  trig << (trig.str().length() ? "+" : "") << "3TOT";
274  if (is3TOTd)
275  trig << (trig.str().length() ? "+" : "") << "3TOTd";
276  if (is3MoPS)
277  trig << (trig.str().length() ? "+" : "") << "3MoPS";
278  if (!is3TOT && !is3TOTd && !is3MoPS && is3TOTMix)
279  trig << (trig.str().length() ? "+" : "") << "3TOTMix";
280  if (is4C1)
281  trig << (trig.str().length() ? "+" : "") << "4C1";
282  } else
283  trig << "None";
284  return trig.str();
285  }
286 
287 
290  {
291  auto topB = CentralConfig::GetInstance()->GetTopBranch("SdEventSelector");
292 
293  topB.GetChild("MinNumberOfStationsAtBeginning").GetData(fMinNumberOfStationsAtBeginning);
294 
295  topB.GetChild("EnableBottomUpSelection").GetData(fEnableBottomUpSelection);
296 
297  topB.GetChild("EnableT4Trigger").GetData(fEnableT4Trigger);
298 
299  topB.GetChild("RejectNonT4Events").GetData(fRejectNonT4Events);
300 
301  topB.GetChild("EnableT5Trigger").GetData(fEnableT5Trigger);
302 
303  topB.GetChild("MinNumberOfActiveStations").GetData(fMinNumberOfActiveStations);
304 
305  topB.GetChild("RejectNonT5Events").GetData(fRejectNonT5Events);
306 
307  topB.GetChild("RejectLightning").GetData(fRejectLightning);
308  switch (fRejectLightning) {
309  case 0:
310  INFO("NOT rejecting stations with potential lightning signal.");
311  break;
312  case 1:
313  INFO("Rejecting individual stations with lightning signal.");
314  break;
315  case 2:
316  INFO("Rejecting whole event when lightning detected.");
317  }
318 
319  topB.GetChild("RejectUBStations").GetData(fRejectUBStations);
320  topB.GetChild("RejectUUBStations").GetData(fRejectUUBStations);
321 
322  if (fRejectUBStations && fRejectUUBStations) {
323  ERROR("Both UB and UUB stations configured for rejection. "
324  "At least one type of electronics must remain selected.");
325  return eFailure;
326  }
327 
328  // bad periods
329  const bool bad = topB.GetChild("EnableSdExcludedPeriods").Get<bool>();
330 
331  fBadPeriods.clear();
332 
333  if (bad) {
334  topB.GetChild("RejectBadPeriods").GetData(fRejectBadPeriods);
335 
336  if (fRejectBadPeriods)
337  INFO("Events in bad periods are rejected.");
338  else
339  INFO("Events in bad periods are tagged.");
340 
341  auto excludedB = CentralConfig::GetInstance()->GetTopBranch("SdExcludedPeriods");
342 
343  for (auto periodB = excludedB.GetFirstChild();
344  periodB; periodB = periodB.GetNextSibling()) {
345  const auto& att = periodB.GetAttributes();
346  const int id = boost::lexical_cast<int>(att.find("id")->second);
347  const TimeStamp begin = periodB.GetChild("begin").Get<TimeStamp>();
348  const TimeStamp end = periodB.GetChild("end").Get<TimeStamp>();
349  fBadPeriods.push_back(SdEventSelectorOG::BadPeriod(id, TimeRange(begin, end)));
350  }
351 
352  if (fBadPeriods.begin() == fBadPeriods.end())
353  WARNING("No excluded periods found.");
354  else {
355  sort(fBadPeriods.begin(), fBadPeriods.end());
356 
357  auto bPrevious = fBadPeriods.begin();
358  const auto bEnd = fBadPeriods.end();
359  if (bPrevious != bEnd) {
360  auto bIt = bPrevious;
361  for (++bIt; bIt != bEnd; ++bIt) {
362  if (bPrevious->HasCommonTime(*bIt)) {
363  ostringstream err;
364  err << "Excluded period "
365  "id=" << bPrevious->GetId() << " "
366  "[" << bPrevious->GetStartTime() << " | " << bPrevious->GetStopTime() << "] "
367  "is in conflict with period "
368  "id=" << bIt->GetId() <<" "
369  "[" << bIt->GetStartTime() << " | " << bIt->GetStopTime() << "].";
370  ERROR(err);
371  return eFailure;
372  }
373  bPrevious = bIt;
374  }
375  }
376  }
377  }
378 
379  // selection parameters
380  topB.GetChild("GridType").GetData(fGridType);
381  switch (fGridType) {
383  INFO("Selecting stations from 1500 m array.");
384  break;
386  INFO("Selecting stations from 750 m array.");
387  break;
389  INFO("Selecting stations from 433 m array.");
390  break;
391  default:
392  ERROR("Unknown GridType!");
393  return eFailure;
394  }
395 
396  topB.GetChild("LightCompatibilityTolerance").GetData(fLightCompatibilityTolerance);
397  topB.GetChild("FirstCrownDistanceRange").GetData(fFirstCrownDistanceRange);
398  topB.GetChild("SkewMaximumDistance").GetData(fSkewMaximumDistance);
399  topB.GetChild("SeedPlaneFrontTimeResidualRangeToT").GetData(fSeedPlaneFrontTimeResidualRangeToT);
400  topB.GetChild("SeedPlaneFrontTimeResidualRangeToTd").GetData(fSeedPlaneFrontTimeResidualRangeToTd);
401  topB.GetChild("SeedPlaneFrontTimeResidualRangeMoPS").GetData(fSeedPlaneFrontTimeResidualRangeMoPS);
402  topB.GetChild("SeedPlaneFrontTimeResidualRangeTh2").GetData(fSeedPlaneFrontTimeResidualRangeTh2);
403  topB.GetChild("SeedPlaneFrontTimeResidualRangeTh1").GetData(fSeedPlaneFrontTimeResidualRangeTh1);
404  topB.GetChild("LonelyIfNoneInDistance").GetData(fLonelyIfNoneInDistance);
405  topB.GetChild("LonelyIfOneInDistance").GetData(fLonelyIfOneInDistance);
406 
407  topB.GetChild("SilenceTOTdStations").GetData(fSilenceTOTdStations);
408  if (fSilenceTOTdStations)
409  INFO("Silencing stations with ToTd-only trigger.");
410 
411  topB.GetChild("SilenceMoPSStations").GetData(fSilenceMoPSStations);
412  if (fSilenceMoPSStations)
413  INFO("Silencing stations with MoPS-only trigger.");
414 
415  const auto silenceNewB = topB.GetChild("SilenceTOTdMoPSTriggersBeforeDate");
416  if (silenceNewB.GetChild("Enabled").Get<bool>()) {
417  silenceNewB.GetChild("Date").GetData(fSilenceTOTdMoPSDate);
418  ostringstream info;
419  info << "Will silence stations with ToTd or MoPS only trigger before the date " << fSilenceTOTdMoPSDate;
420  INFO(info);
421  }
422 
423  return eSuccess;
424  }
425 
426 
428  SdEventSelector::Run(evt::Event& event)
429  {
430  auto& namedCounters = RunController::GetInstance().GetRunData().GetNamedCounters();
431 
432  if (!event.HasSEvent()) {
433  ++namedCounters["SdEventSelector/NoSdEvent"];
434  return eContinueLoop;
435  }
436 
437  auto& sEvent = event.GetSEvent();
438 
439  // station selection
440  const auto nStations = StationSelection(sEvent);
441  if (nStations < fMinNumberOfStationsAtBeginning) {
442  ostringstream info;
443  info << "Not enough stations (" << nStations << " < " << fMinNumberOfStationsAtBeginning << ")!";
444  INFO(info);
445  ++namedCounters["SdEventSelector/NotEnoughStations"];
446  return eContinueLoop;
447  }
448 
449  fCandidateStations.clear();
450  f3TOTCandidateStations.clear();
451  f3TOTdCandidateStations.clear();
452  f3MoPSCandidateStations.clear();
453  f3TOTMixCandidateStations.clear();
454  f4C1CandidateStations.clear();
455  fSeedStations.clear();
456 
457  const bool isFD = sEvent.GetTrigger().IsFD();
458 
459  if (isFD)
460  ++namedCounters["SdEventSelector/FdTrigger"];
461 
462  const auto& eventTime = sEvent.GetHeader().GetTime();
463  if (fSilenceTOTdMoPSDate) {
464  if (eventTime < fSilenceTOTdMoPSDate) {
465  fSilenceTOTdStations = true;
466  fSilenceMoPSStations = true;
467  } else {
468  fSilenceTOTdStations = false;
469  fSilenceMoPSStations = false;
470  }
471  }
472 
473  auto& shSRec = GetSRecShower(event);
474  shSRec.SetIsTOTdMoPSSilent(fSilenceTOTdStations && fSilenceMoPSStations);
475 
476  const auto& sDet = det::Detector::GetInstance().GetSDetector();
477 
478  // prepare station lists
479  for (auto& s : sEvent.CandidateStationsRange()) {
480  const auto& sTrig = s.GetTriggerData();
481  const auto& ds = sDet.GetStation(s);
482  const StationPair sp(&s, &ds);
483  fCandidateStations.push_back(sp);
484  if (sTrig.IsT2() || isFD) {
485  f4C1CandidateStations.push_back(sp);
486  if (sTrig.IsTimeOverThreshold())
487  f3TOTCandidateStations.push_back(sp);
488  if (sTrig.IsTimeOverThresholdDeconvoluted() && !fSilenceTOTdStations)
489  f3TOTdCandidateStations.push_back(sp);
490  if (sTrig.IsMultiplicityOfPositiveSteps() && !fSilenceMoPSStations)
491  f3MoPSCandidateStations.push_back(sp);
492  if (sTrig.IsTimeOverThreshold() ||
493  (sTrig.IsTimeOverThresholdDeconvoluted() && !fSilenceTOTdStations) ||
494  (sTrig.IsMultiplicityOfPositiveSteps() && !fSilenceMoPSStations))
495  f3TOTMixCandidateStations.push_back(sp);
496  }
497  }
498 
499  const bool is3TOT = IsSEvent3TOT(f3TOTCandidateStations);
500  const bool is3TOTd = IsSEvent3TOT(f3TOTdCandidateStations);
501  const bool is3MoPS = IsSEvent3TOT(f3MoPSCandidateStations);
502  const bool is3TOTMix = IsSEvent3TOT(f3TOTMixCandidateStations); // superset of is3TOT is3TOTd is3MoPS
503 
504  if (is3TOT)
505  ++namedCounters["SdEventSelector/3TOT"];
506  if (is3TOTd)
507  ++namedCounters["SdEventSelector/3TOTd"];
508  if (is3MoPS)
509  ++namedCounters["SdEventSelector/3MoPS"];
510  if (is3TOTMix)
511  ++namedCounters["SdEventSelector/3TOTMix"];
512 
513  if (fEnableBottomUpSelection && !BottomUpSelection(is3TOTMix, event)) {
514  INFO("Bottom-up-selection failed!");
515  ++namedCounters["SdEventSelector/BottomUpSelectionFailed"];
516  return eContinueLoop;
517  }
518 
519  {
520  int lonely = 0;
521  while (RejectLonelyStations())
522  ++lonely;
523  if (lonely)
524  ++namedCounters["SdEventSelector/LonelyStationEvents"];
525  }
526 
527  ostringstream info;
528 
529  int t4TriggerPattern = 0;
530  if (fEnableT4Trigger) {
531 
532  const bool is4C1 = IsSEvent4C1();
533  const bool isT4 = is3TOTMix || is4C1;
534 
535  info << "T4 = "
536  << GetT4TriggerName(isT4, isFD, is3TOT, is3TOTd, is3MoPS, is3TOTMix, is4C1);
537 
538  if (is4C1)
539  ++namedCounters["SdEventSelector/4C1"];
540  if (isT4)
541  ++namedCounters["SdEventSelector/T4"];
542 
543  if (fRejectNonT4Events && !isT4) {
544  INFO(info);
545  return eContinueLoop;
546  }
547 
548  t4TriggerPattern =
549  (isFD * ShowerSRecData::eT4_FD) |
550  (is3TOT * ShowerSRecData::eT4_3TOT) |
551  (is3TOTd * ShowerSRecData::eT4_3TOTd) |
552  (is3MoPS * ShowerSRecData::eT4_3MoPS) |
553  (is3TOTMix * ShowerSRecData::eT4_3TOTMix) |
554  (is4C1 * ShowerSRecData::eT4_4C1);
555 
556  shSRec.SetT4Trigger(t4TriggerPattern);
557  shSRec.SetReconstructionSeed(fSeedStations);
558 
559  }
560 
561  if (fEnableT5Trigger) {
562 
563  fCandidateStations.clear();
564 
565  for (auto& s : sEvent.CandidateStationsRange()) {
566  const auto& ds = sDet.GetStation(s);
567  fCandidateStations.emplace_back(&s, &ds);
568  }
569 
570  const auto t5Stations = CalculateT5Trigger(sEvent);
571  const unsigned int hottestStation = t5Stations.first;
572  const int nActive = t5Stations.second.size();
573  const bool t5 = (hottestStation && nActive >= fMinNumberOfActiveStations);
574 
575  // Fill vector denoting which T5 neighbor stations were UUBs
576  vector<int> t5NeighborsUUB;
577  for (const auto sid : t5Stations.second) {
578  const bool isUUB = sDet.GetStation(sid).IsUUB();
579  if (isUUB)
580  t5NeighborsUUB.push_back(sid);
581  }
582 
583  info << (info.str().length() ? "; " : "")
584  << "T5 = " << t5 << ", "
585  << nActive << "T5, "
586  "stations = " << hottestStation << "(hottest)";
587  for (const auto id : t5Stations.second) {
588  const auto& s = sEvent.GetStation(id);
589  info << ' ' << id << '('
590  << (s.IsCandidate() ?
591  "candidate" :
592  (s.IsSilent() ?
593  "silent" :
594  ("rejected:" +
596  )
597  ) << ')';
598  }
599 
600  if (t5)
601  ++namedCounters["SdEventSelector/T5"];
602 
603  if (fRejectNonT5Events && !t5) {
604  INFO(info);
605  return eContinueLoop;
606  }
607 
608  shSRec.SetT5Trigger(t5*ShowerSRecData::eT5_Prior);
609  shSRec.SetT5HottestStation(hottestStation);
610  shSRec.SetT5PriorActiveNeighbors(t5Stations.second);
611  shSRec.SetT5PriorActiveUUBNeighbors(t5NeighborsUUB);
612 
613  }
614 
615  const int id = GetBadPeriod(eventTime);
616  if (id) {
617  event.GetRecShower().GetSRecShower().SetBadPeriodId(id);
618  ++namedCounters["SdEventSelector/BadPeriodEvents"];
619  info << "; Bad period id=" << id;
620  INFO(info);
621  if (fRejectBadPeriods)
622  return eContinueLoop;
623  }
624 
625  if (!info.str().empty())
626  INFO(info);
627 
628  ++namedCounters["SdEventSelector/SelectedEvent"];
629 
630  return eSuccess;
631  }
632 
633 
635  SdEventSelector::Finish()
636  {
637  return eSuccess;
638  }
639 
640 
641  int
642  SdEventSelector::GetBadPeriod(const TimeStamp& time)
643  const
644  {
645  if (fBadPeriods.empty())
646  return 0;
647 
648  // gives first period not less than time
649  auto low =
650  lower_bound(fBadPeriods.begin(), fBadPeriods.end(), TimeRange(time, time));
651 
652  if (low == fBadPeriods.begin())
653  return 0;
654 
655  // check if the last period less than time contains time
656  --low;
657  return low->IsInRange(time) ? low->GetId() : 0;
658  }
659 
660 
661  /*
662  to find 3TOT we need a triangle with (for shells see the table at top):
663  - 3 edges from shell 1 (basic equilateral triangle) or
664  - 2 edges from shell 1 and one from shell 2 (stretched triangle)
665  */
666  bool
667  SdEventSelector::IsSEvent3TOT(const StationPairList& candidateStations)
668  const
669  {
670  if (candidateStations.size() < 3)
671  return false;
672 
673  const auto spBegin = candidateStations.begin();
674  for (auto spIt = spBegin, spEnd = candidateStations.end(); spIt != spEnd; ++spIt) {
675 
676  const auto& si = *spIt->first;
677  const auto& dsi = *spIt->second;
678 
679  for (auto spJt = spBegin; spJt != spEnd; ++spJt) {
680  if (spJt == spIt)
681  continue;
682 
683  const auto& sj = *spJt->first;
684  const auto& dsj = *spJt->second;
685 
686  // require i-j ~ 1500 m
687  const double distij = Distance(dsi, dsj);
688  if (distij < fFirstCrownDistanceRange[0] || distij > fFirstCrownDistanceRange[1] ||
689  distij < CTimeDifferenceMargin(si, sj))
690  continue;
691 
692  for (auto spKt = spBegin; spKt != spEnd; ++spKt) {
693  if (spKt == spJt || spKt == spIt)
694  continue;
695 
696  const auto& sk = *spKt->first;
697  const auto& dsk = *spKt->second;
698 
699  // require i-k ~ 1500 m
700  const double distik = Distance(dsi, dsk);
701  if (distik < fFirstCrownDistanceRange[0] || distik > fFirstCrownDistanceRange[1] ||
702  distik < CTimeDifferenceMargin(si, sk))
703  continue;
704 
705  // require j-k ~ 1500 or 2600 m
706  const double distjk = Distance(dsj, dsk);
707  if (distjk < fFirstCrownDistanceRange[0] || distjk > fSkewMaximumDistance ||
708  distjk < CTimeDifferenceMargin(sj, sk))
709  continue;
710 
711  // Found a 3TOT
712  return true;
713  }
714  }
715  }
716 
717  return false;
718  }
719 
720 
721  /*
722  for 4C1 configuration we have to find a station (si) with 3 neighbors from
723  shell 1 (sj, sk, sl)
724  */
725  bool
726  SdEventSelector::IsSEvent4C1()
727  const
728  {
729  if (f4C1CandidateStations.size() < 4)
730  return false;
731 
732  const auto spBegin = f4C1CandidateStations.begin();
733  for(auto spIt = spBegin, spEnd = f4C1CandidateStations.end(); spIt != spEnd; ++spIt) {
734 
735  const auto& si = *spIt->first;
736  const auto& dsi = *spIt->second;
737 
738  for (auto spJt = spBegin; spJt != spEnd; ++spJt) {
739  if (spJt == spIt)
740  continue;
741 
742  const auto& sj = *spJt->first;
743  const auto& dsj = *spJt->second;
744 
745  // require i-j ~ 1500 m
746  const double distij = Distance(dsi, dsj);
747  if (distij < fFirstCrownDistanceRange[0] || distij > fFirstCrownDistanceRange[1] ||
748  distij < CTimeDifferenceMargin(si, sj))
749  continue;
750 
751  for (auto spKt = Next(spJt); spKt != spEnd; ++spKt) {
752  if (spKt == spIt)
753  continue;
754 
755  const auto& sk = *spKt->first;
756  const auto& dsk = *spKt->second;
757 
758  // require i-k ~ 1500 m
759  const double distik = Distance(dsi, dsk);
760  if (distik < fFirstCrownDistanceRange[0] || distik > fFirstCrownDistanceRange[1] ||
761  distik < CTimeDifferenceMargin(si, sk))
762  continue;
763 
764  if (Distance(dsj, dsk) < CTimeDifferenceMargin(sj, sk))
765  continue;
766 
767  for (auto spLt = Next(spKt); spLt != spEnd; ++spLt) {
768  if (spLt == spIt)
769  continue;
770 
771  const auto& sl = *spLt->first;
772  const auto& dsl =*spLt->second;
773 
774  // require i-l ~ 1500 m
775  const double distil = Distance(dsi, dsl);
776  if (distil < fFirstCrownDistanceRange[0] || distil > fFirstCrownDistanceRange[1] ||
777  distil < CTimeDifferenceMargin(si, sl))
778  continue;
779 
780  if (Distance(dsj, dsl) < CTimeDifferenceMargin(sj, sl))
781  continue;
782 
783  if (Distance(dsk, dsl) < CTimeDifferenceMargin(sk, sl))
784  continue;
785 
786  // found 4C1
787  return true;
788  }
789  }
790  }
791  }
792 
793  return false;
794  }
795 
796 
797  pair<int, vector<int>> // hottest station id, number of active neighbors
798  SdEventSelector::CalculateT5Trigger(const SEvent& sEvent)
799  const
800  {
801  const Station* maxStation = nullptr;
802  {
803  double maxSignal = 0;
804  for (const auto& s : sEvent.CandidateStationsRange()) {
805  const double signal = s.GetRecData().GetTotalSignal();
806  if (maxSignal < signal) {
807  maxSignal = signal;
808  maxStation = &s;
809  }
810  }
811 
812  if (!maxStation) {
813  INFO("No station with maximal signal found");
814  return make_pair(0U, vector<int>());
815  }
816  }
817 
818  const auto& sDet = det::Detector::GetInstance().GetSDetector();
819  const auto maxPos = sDet.GetStation(*maxStation).GetPosition();
820 
821  const auto badBits = ~StationConstants::kGoodBitsT5;
822 
823  pair<unsigned int, vector<int>> ret;
824  ret.first = maxStation->GetId();
825  auto& functioningNeighbors = ret.second;
826  unsigned int nCandidates = 0;
827  unsigned int nSilent = 0;
828  unsigned int nRejected = 0;
829  for (const auto& s : sEvent.StationsRange()) {
830  if (!s.IsRejected() || !(s.GetRejectionStatus() & badBits)) {
831  const auto& pos = sDet.GetStation(s).GetPosition();
832  const double dist = Distance(maxPos, pos);
833  if (fFirstCrownDistanceRange[0] < dist && dist < fFirstCrownDistanceRange[1]) {
834  functioningNeighbors.push_back(s.GetId());
835  nCandidates += s.IsCandidate();
836  nSilent += s.IsSilent();
837  nRejected += s.IsRejected();
838  }
839  }
840  }
841 
842  if (int(functioningNeighbors.size()) < fMinNumberOfActiveStations) {
843  ostringstream info;
844  info << "Only " << functioningNeighbors.size() << " "
845  "(out of " << fMinNumberOfActiveStations << ") "
846  "functioning neighbors for max-signal station "
847  << maxStation->GetId() << " found "
848  "(candidates: " << nCandidates << ", "
849  "silent: " << nSilent << ", "
850  "rejected: " << nRejected << ").";
851  INFO(info);
852  }
853 
854  return ret;
855  }
856 
857 
858  bool
859  SdEventSelector::BottomUpSelection(const bool is3TOTMix, Event& event)
860  {
861  // must have valid f3TOTMixCandidateStations!
862 
863  set<StationPair> all4C1Stations;
864 
865  if (!is3TOTMix && f4C1CandidateStations.size() >= 4) {
866  // repeat 4C1 search and find ALL stations that satisfy 4C1 condition
867 
868  const auto spBegin = f4C1CandidateStations.begin();
869  for (auto spIt = spBegin, spEnd = f4C1CandidateStations.end(); spIt != spEnd; ++spIt) {
870 
871  const auto& si = *spIt->first;
872  const auto& dsi = *spIt->second;
873 
874  for (auto spJt = spBegin; spJt != spEnd; ++spJt) {
875  if (spJt == spIt)
876  continue;
877 
878  const auto& sj = *spJt->first;
879  const auto& dsj = *spJt->second;
880 
881  // require i-j ~ 1500 m
882  const double distij = Distance(dsi, dsj);
883  if (distij < fFirstCrownDistanceRange[0] || distij > fFirstCrownDistanceRange[1] ||
884  distij < CTimeDifferenceMargin(si, sj))
885  continue;
886 
887  for (auto spKt = Next(spJt); spKt != spEnd; ++spKt) {
888  if (spKt == spIt)
889  continue;
890 
891  const auto& sk = *spKt->first;
892  const auto& dsk = *spKt->second;
893 
894  // require i-k ~ 1500 m
895  const double distik = Distance(dsi, dsk);
896  if (distik < fFirstCrownDistanceRange[0] || distik > fFirstCrownDistanceRange[1] ||
897  distik < CTimeDifferenceMargin(si, sk))
898  continue;
899 
900  if (Distance(dsj, dsk) < CTimeDifferenceMargin(sj, sk))
901  continue;
902 
903  for (auto spLt = Next(spKt); spLt != spEnd; ++spLt) {
904  if (spLt == spIt)
905  continue;
906 
907  const auto& sl = *spLt->first;
908  const auto& dsl =*spLt->second;
909 
910  // require i-l ~ 1500 m
911  const double distil = Distance(dsi, dsl);
912  if (distil < fFirstCrownDistanceRange[0] || distil > fFirstCrownDistanceRange[1] ||
913  distil < CTimeDifferenceMargin(si, sl))
914  continue;
915 
916  if (Distance(dsj, dsl) < CTimeDifferenceMargin(sj, sl))
917  continue;
918 
919  if (Distance(dsk, dsl) < CTimeDifferenceMargin(sk, sl))
920  continue;
921 
922  all4C1Stations.insert(*spIt);
923  all4C1Stations.insert(*spJt);
924  all4C1Stations.insert(*spKt);
925  all4C1Stations.insert(*spLt);
926  } // for spLt
927  } // for spKt
928  } // for spJt
929  } // for spIt
930 
931  } // if not 3TOT
932 
933  fSeedStations.clear();
934 
935  // add stations above
936  for (const auto& sp : all4C1Stations) {
937  const auto e = f3TOTMixCandidateStations.end();
938  if (find(f3TOTMixCandidateStations.begin(), e, sp) == e)
939  f3TOTMixCandidateStations.push_back(sp);
940  }
941 
942  if (f3TOTMixCandidateStations.size() < 3) {
943  INFO("No seed found.");
944  return false;
945  }
946 
947  double maxSignalSum = 0;
948  StationPair seed[3] = { StationPair(0, 0) };
949 
950  // find triangle (3TOT && 4C1 above) seed stations
951  const auto spBegin = f3TOTMixCandidateStations.begin();
952  for (auto spIt = spBegin, spEnd = f3TOTMixCandidateStations.end(); spIt != spEnd; ++spIt) {
953 
954  const auto& si = *spIt->first;
955  const auto& dsi = *spIt->second;
956 
957  for (auto spJt = spBegin; spJt != spEnd; ++spJt) {
958 
959  if (spJt == spIt)
960  continue;
961 
962  const auto& sj = *spJt->first;
963  const auto& dsj = *spJt->second;
964 
965  const double distij = Distance(dsi, dsj);
966 
967  // require i-j ~ 1500 m
968  if (distij < fFirstCrownDistanceRange[0] || distij > fFirstCrownDistanceRange[1] ||
969  distij < CTimeDifferenceMargin(si, sj))
970  continue;
971 
972  for (auto spKt = spBegin; spKt != spEnd; ++spKt) {
973 
974  if (spKt == spIt || spKt == spJt)
975  continue;
976 
977  const auto& sk = *spKt->first;
978  const auto& dsk = *spKt->second;
979 
980  const double distik = Distance(dsi, dsk);
981 
982  // require i-k ~ 1500 m
983  if (distik < fFirstCrownDistanceRange[0] || distik > fFirstCrownDistanceRange[1] ||
984  distik < CTimeDifferenceMargin(si, sk))
985  continue;
986 
987  const double distjk = Distance(dsj, dsk);
988 
989  if (distjk < fFirstCrownDistanceRange[0] || distjk > fSkewMaximumDistance ||
990  distjk < CTimeDifferenceMargin(sj, sk))
991  continue;
992 
993  const double sigi = si.GetRecData().GetTotalSignal();
994  const double sigj = sj.GetRecData().GetTotalSignal();
995  const double sigk = sk.GetRecData().GetTotalSignal();
996  const double signalSum = sigi + sigj + sigk;
997 
998  if (signalSum > maxSignalSum) {
999  maxSignalSum = signalSum;
1000  // find max
1001  if (sigi > sigj) {
1002  if (sigi > sigk) {
1003  seed[0] = *spIt;
1004  seed[1] = *spJt;
1005  seed[2] = *spKt;
1006  } else {
1007  seed[0] = *spKt;
1008  seed[1] = *spIt;
1009  seed[2] = *spJt;
1010  }
1011  } else {
1012  if (sigj > sigk) {
1013  seed[0] = *spJt;
1014  seed[1] = *spIt;
1015  seed[2] = *spKt;
1016  } else {
1017  seed[0] = *spKt;
1018  seed[1] = *spIt;
1019  seed[2] = *spJt;
1020  }
1021  }
1022  }
1023 
1024  } // for spKt
1025  } // for spJt
1026  } // for spIt
1027 
1028  if (!seed[0].first) {
1029 
1030  INFO("No seed found.");
1031  return false;
1032 
1033  } else {
1034 
1035  fSeedStations.resize(3);
1036  for (int i = 0; i < 3; ++i)
1037  fSeedStations[i] = seed[i].first->GetId();
1038 
1039  const auto& s1 = *seed[0].first;
1040  const auto& t1 = s1.GetRecData().GetSignalStartTime();
1041  const auto& x1 = seed[0].second->GetPosition();
1042 
1043  const auto& s2 = *seed[1].first;
1044  const double ct12 =
1045  kSpeedOfLight*(t1 - s2.GetRecData().GetSignalStartTime()).GetInterval();
1046  const auto x21 = seed[1].second->GetPosition() - x1;
1047 
1048  const auto& s3 = *seed[2].first;
1049  const double ct13 =
1050  kSpeedOfLight*(t1 - s3.GetRecData().GetSignalStartTime()).GetInterval();
1051  const auto x31 = seed[2].second->GetPosition() - x1;
1052 
1053  const double sx21 = x21.GetMag();
1054  const auto vi = x21 / sx21;
1055  const double taui = ct12/sx21;
1056  const double sx31 = x31.GetMag();
1057  const auto vj = x31 / sx31;
1058  const double tauj = ct13/sx31;
1059  const double ij = vi*vj;
1060  const double d = 1 - ij*ij;
1061  const double gamma2 = (1 - (taui*taui - 2*ij*taui*tauj + tauj*tauj)/d)/d;
1062 
1063  const auto& siteCS = det::Detector::GetInstance().GetSiteCoordinateSystem();
1064 
1065  Vector axis;
1066 
1067  if (gamma2 >= 0) {
1068 
1069  const double alpha = (taui - tauj*ij) / d;
1070  const double beta = (tauj - taui*ij) / d;
1071  const double gamma = sqrt(gamma2);
1072  Vector vk = Cross(vi, vj);
1073  // flip to zenith side
1074  if (vk.GetZ(siteCS) < 0)
1075  vk *= -1;
1076  axis = alpha*vi + beta*vj + gamma*vk;
1077 
1078  } else {
1079 
1080  // fit
1081  INFO("Unphysical seed, trying minimization.");
1082 
1083  TMinuit minuit(1);
1084  int errFlag = 0;
1085  double argList[10];
1086  argList[0] = -1;
1087  minuit.mnexcm("SET PRINTOUT", argList, 1, errFlag);
1088  minuit.mnexcm("SET NOWARNINGS", argList, 0, errFlag);
1089  minuit.SetPrintLevel(-1);
1090 
1091  const auto vk = Normalized(vj - ij * vi);
1092 
1093  minuit.SetFCN(SeedFit::Chi2);
1095  const double jk = vj * vk;
1097  SeedFit::gTimeI = taui;
1098  SeedFit::gTimeJ = tauj;
1099 
1100  argList[0] = 1;
1101  minuit.mnexcm("SET ERRORDEF", argList, 1, errFlag);
1102 
1103  const double phi0 = atan2(tauj*jk, taui + tauj*ij);
1104  minuit.mnparm(0, "phi", phi0, 0.5, 0, 0, errFlag);
1105 
1106  argList[0] = 500;
1107  minuit.mnexcm("MINIMIZE", argList, 1, errFlag);
1108  if (errFlag) {
1109  minuit.mnexcm("MINOS", argList, 0, errFlag);
1110  if (errFlag)
1111  return false;
1112  }
1113 
1114  double phi;
1115  double phiErr;
1116  minuit.GetParameter(0, phi, phiErr);
1117 
1118  const double u = cos(phi);
1119  const double v = sin(phi);
1120  axis = u * vi + v * vk;
1121  }
1122 
1123  {
1124  ostringstream info;
1125  info << "Seed theta = " << axis.GetTheta(siteCS)/degree << " deg, "
1126  "phi = " << axis.GetPhi(siteCS)/degree << " deg (site)";
1127  INFO(info);
1128  }
1129 
1130  auto& ssRec = GetSRecShower(event);
1131  ssRec.SetSeedAxis(axis);
1132  ssRec.SetSeedBarycenter(x1 + (1/3.)*(x21 + x31));
1133  // find accidentals
1134  map<int, double> rejected;
1135  for (auto spIt = fCandidateStations.begin(); spIt != fCandidateStations.end(); ) {
1136  auto& s = *spIt->first;
1137  const double delay =
1138  (s.GetRecData().GetSignalStartTime() - t1).GetInterval() +
1139  (axis*(spIt->second->GetPosition() - x1)) / kSpeedOfLight;
1140 
1141  s.SetBottomUpResidual(delay);
1142 
1143  // is delay within [Early, Late]
1144  const auto& sTrig = s.GetTriggerData();
1145  if ((sTrig.IsTimeOverThreshold() && IsInRange(delay, fSeedPlaneFrontTimeResidualRangeToT)) ||
1146  (sTrig.IsTimeOverThresholdDeconvoluted() && IsInRange(delay, fSeedPlaneFrontTimeResidualRangeToTd)) ||
1147  (sTrig.IsMultiplicityOfPositiveSteps() && IsInRange(delay, fSeedPlaneFrontTimeResidualRangeMoPS)) ||
1148  (sTrig.IsT2Threshold() && IsInRange(delay, fSeedPlaneFrontTimeResidualRangeTh2)) ||
1149  (sTrig.IsT1Threshold() && IsInRange(delay, fSeedPlaneFrontTimeResidualRangeTh1)))
1150  ++spIt;
1151  else {
1152  s.SetRejected(StationConstants::eOutOfTime);
1153  rejected[s.GetId()] = delay;
1154  f3TOTMixCandidateStations.remove(*spIt);
1155  f4C1CandidateStations.remove(*spIt);
1156  spIt = fCandidateStations.erase(spIt);
1157  }
1158  }
1159 
1160  if (!rejected.empty()) {
1161  ostringstream info;
1162  info << "Station" << String::Plural(rejected)
1163  << " not compatible with seed reconstruction:\n";
1164  TabularStream tab("r|.");
1165  tab << endc << "time" << endr
1166  << "station" << endc << "diff [ns]" << endr << hline;
1167  for (const auto& r : rejected)
1168  tab << r.first << ' ' << endc << ' ' << r.second/nanosecond << endr;
1169  tab << delr;
1170  info << tab;
1171  INFO(info);
1172  }
1173 
1174  }
1175 
1176  return true;
1177  }
1178 
1179 
1180  bool
1181  SdEventSelector::RejectLonelyStations()
1182  {
1183  vector<int> ssLonely;
1184 
1185  for (auto spIt = fCandidateStations.begin(); spIt != fCandidateStations.end(); ) {
1186  const auto& dsi = *spIt->second;
1187  int closeNeighbors = 0;
1188  int remoteNeighbors = 0;
1189  for (auto spJt = fCandidateStations.begin(); spJt != fCandidateStations.end(); ++spJt) {
1190  if (spJt == spIt)
1191  continue;
1192  const double distij = Distance(dsi, *spJt->second);
1193  if (distij < fLonelyIfNoneInDistance)
1194  ++closeNeighbors;
1195  if (distij < fLonelyIfOneInDistance)
1196  ++remoteNeighbors;
1197  }
1198  if (!closeNeighbors || remoteNeighbors <= 1) {
1199  auto& s = *spIt->first;
1200  ssLonely.push_back(s.GetId());
1201  s.SetRejected(StationConstants::eLonely);
1202  f3TOTMixCandidateStations.remove(*spIt);
1203  f4C1CandidateStations.remove(*spIt);
1204  spIt = fCandidateStations.erase(spIt);
1205  } else
1206  ++spIt;
1207  }
1208 
1209  if (!ssLonely.empty()) {
1210  ostringstream info;
1211  info << String::OfSortedIds(ssLonely) << " rejected as lonely.";
1212  INFO(info);
1213  return true;
1214  }
1215 
1216  return false;
1217  }
1218 
1219 }
AxialVector Cross(const Vector &l, const Vector &r)
Definition: OperationsAV.h:25
int GetId() const
Get the station Id.
const double degree
constexpr T Sqr(const T &x)
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
Detector description interface for Station-related data.
Time interval defined by two TimeStamps.
Definition: TimeRange.h:23
ShowerSRecData & GetSRecShower(evt::Event &event)
Interface class to access to the SD Reconstruction of a Shower.
Iterator Next(Iterator it)
bool HasRecShower() const
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
sevt::StationRecData & GetRecData()
Get station level reconstructed data.
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
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 Chi2(int &, double *const , double &value, double *const par, const int)
std::list< StationPair > StationPairList
#define U
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
string GetT4TriggerName(const bool isT4, const bool isFD, const bool is3TOT, const bool is3TOTd, const bool is3MoPS, const bool is3TOTMix, const bool is4C1)
utl::Point GetPosition() const
Tank position.
const char * Plural(const T n)
Definition: String.h:104
AttributeMap GetAttributes() const
Get a map&lt;string, string&gt; containing all the attributes of this Branch.
Definition: Branch.cc:267
class to hold data at Station level
std::string AsBinary(const T &number, const int maxBits=8 *sizeof(T), const char separator= ' ', const int stride=4)
converts integer-type numbers into a string of binary representation
Definition: String.h:135
constexpr double s
Definition: AugerUnits.h:163
utl::TimeStamp GetSignalStartTime() const
Start time of the signal.
static int delay
Definition: XbAlgo.cc:20
constexpr double nanosecond
Definition: AugerUnits.h:143
double abs(const SVector< n, T > &v)
const EndRow endr
const int tab
Definition: SdInspector.cc:35
class to format data in tabular form
#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
AxialVector Normalized(const AxialVector &v)
Definition: AxialVector.h:81
double Distance(const Point &p, const sdet::Station &s)
constexpr double kSpeedOfLight
void MakeInfo(const vector< int > &ids, const string &message)
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
const double low[npar]
Definition: UnivRec.h:77
const DeleteRow delr
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
Vector object.
Definition: Vector.h:30
bool IsInRange(const double x, const vector< double > &r)
std::pair< sevt::Station *, const sdet::Station * > StationPair
string OfSortedIds(vector< int > ids)
Definition: String.cc:65
bool IsLightning(const Station &station)
Definition: IsLightning.cc:22
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
const HLine hline('-')
const EndColumn endc
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.