Belle II Software  release-06-00-14
eclHadronTimeCalibrationValidationCollectorModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 
10 #include <ecl/modules/eclHadronTimeCalibrationValidationCollector/eclHadronTimeCalibrationValidationCollectorModule.h>
11 #include <framework/dataobjects/EventMetaData.h>
12 #include <framework/gearbox/Const.h>
13 #include <ecl/dataobjects/ECLDigit.h>
14 #include <ecl/dataobjects/ECLCalDigit.h>
15 #include <ecl/dataobjects/ECLTrig.h>
16 #include <mdst/dataobjects/ECLCluster.h>
17 #include <mdst/dataobjects/Track.h>
18 #include <mdst/dataobjects/HitPatternCDC.h>
19 #include <ecl/digitization/EclConfiguration.h>
20 
21 #include <boost/optional.hpp>
22 
23 #include <TH2F.h>
24 #include <TTree.h>
25 #include <TFile.h>
26 
27 using namespace Belle2;
28 using namespace ECL;
29 using namespace std;
30 
31 //-----------------------------------------------------------------
32 // Register the Module
33 //-----------------------------------------------------------------
34 REG_MODULE(eclHadronTimeCalibrationValidationCollector)
35 
36 //-----------------------------------------------------------------
37 // Implementation
38 //-----------------------------------------------------------------
39 
42  m_dbg_tree_photonClusters(0),
43  m_dbg_tree_event(0),
44  m_tree_evt_num(0)//,
45  //m_GammaGammaECalib("ECLCrystalEnergyGammaGamma")
46 {
47  setDescription("This module validates the ECL cluster times");
48 
49  addParam("timeAbsMax", m_timeAbsMax, // (Time in ns)
50  "Events with fabs(getTimeFit) > m_timeAbsMax "
51  "are excluded", (short)80);
52 
53  addParam("saveTree", m_saveTree,
54  "If true, TTree 'tree' with more detailed event info is saved in "
55  "the output file specified by HistoManager",
56  false);
57 
58  addParam("looseTrkZ0", m_looseTrkZ0, "max Z0 for loose tracks (cm)", 10.);
59  addParam("tightTrkZ0", m_tightTrkZ0, "max Z0 for tight tracks (cm)", 2.);
60  addParam("looseTrkD0", m_looseTrkD0, "max D0 for loose tracks (cm)", 2.);
61  addParam("tightTrkD0", m_tightTrkD0, "max D0 for tight tracks (cm)", 0.5); // beam pipe radius = 1cm in 2019
62 
63 
64  // specify this flag if you need parallel processing
65  setPropertyFlags(c_ParallelProcessingCertified);
66 }
67 
69 {
70 }
71 
73 {
74 
75  //=== Prepare TTree for debug output
76  if (m_saveTree) {
77  // Per photon cluster
78  m_dbg_tree_photonClusters = new TTree("tree_photonClusters",
79  "Validating crystal and crate time calibrations using photon clusters in events with lots of tracks and clusters") ;
80  m_dbg_tree_photonClusters->Branch("EventNum" , &m_tree_evt_num) ->SetTitle("Event number") ;
81  m_dbg_tree_photonClusters->Branch("cluster_time" , &m_tree_time) ->SetTitle("Cluster time t (calibrated), ns") ;
82  m_dbg_tree_photonClusters->Branch("clust_E" , &m_E_photon_clust) ->SetTitle("Photon type cluster energy, GeV") ;
83  m_dbg_tree_photonClusters->Branch("Ntracks" , &m_NtightTracks) ->SetTitle("Number of tracks") ;
84  m_dbg_tree_photonClusters->Branch("NphotonClusters" , &m_NphotonClusters) ->SetTitle("Number of photons") ;
85  m_dbg_tree_photonClusters->Branch("NGoodClusters" , &m_NGoodClusters) ->SetTitle("Number of good ECL clusters") ;
86  m_dbg_tree_photonClusters->Branch("t0" , &m_tree_t0) ->SetTitle("T0, ns") ;
87  m_dbg_tree_photonClusters->Branch("t0_unc" , &m_tree_t0_unc) ->SetTitle("T0 uncertainty, ns") ;
88  m_dbg_tree_photonClusters->Branch("runNum" , &m_tree_run) ->SetTitle("Run number") ;
89  m_dbg_tree_photonClusters->Branch("CrystalCellID" , &m_tree_cid) ->SetTitle("Cell ID, 1..8736") ;
90  m_dbg_tree_photonClusters->Branch("dt99" , &m_tree_dt99) ->SetTitle("Cluster dt99, ns") ;
91  m_dbg_tree_photonClusters->SetAutoSave(10) ;
92 
93  // Per event
94  m_dbg_tree_event = new TTree("tree_event",
95  "Validating crystal and crate time calibrations using photon clusters in events with lots of tracks and clusters") ;
96  m_dbg_tree_event->Branch("EventNum" , &m_tree_evt_num) ->SetTitle("Event number") ;
97  m_dbg_tree_event->Branch("t0" , &m_tree_t0) ->SetTitle("T0, ns") ;
98  m_dbg_tree_event->Branch("t0_unc" , &m_tree_t0_unc) ->SetTitle("T0 uncertainty, ns") ;
99  m_dbg_tree_event->Branch("runNum" , &m_tree_run) ->SetTitle("Run number") ;
100  m_dbg_tree_event->Branch("Ntracks" , &m_NtightTracks) ->SetTitle("Number of tracks") ;
101  m_dbg_tree_event->Branch("NphotonClusters" , &m_NphotonClusters) ->SetTitle("Number of photons") ;
102  m_dbg_tree_event->Branch("NGoodClusters" , &m_NGoodClusters) ->SetTitle("Number of good ECL clusters") ;
103  m_dbg_tree_event->Branch("E0" , &m_tree_E0) ->SetTitle("Highest E cluster E") ;
104  m_dbg_tree_event->Branch("time_E0" , &m_tree_time_fromE0) ->SetTitle("Cluster time of highest E cluster") ;
105  m_dbg_tree_event->SetAutoSave(10) ;
106  }
107 }
108 
110 {
111  //=== MetaData
112  StoreObjPtr<EventMetaData> evtMetaData ;
113  B2INFO("eclHadronTimeCalibrationValidationCollector: Experiment = " << evtMetaData->getExperiment() <<
114  " run = " << evtMetaData->getRun()) ;
115 
116  //=== Create histograms and register them in the data store
117 
118  // Define the bin size, which is equivalent to the
119  double binSize = 2000.0 / pow(2, 12);
120  double halfBinSize = binSize / 2.0;
121 
122  /* Determine the number of bins required to go from the edge of the bin centred
123  on zero to a value just larger than the negative cut off */
124  double nBinsNeg = floor((m_timeAbsMax - halfBinSize) / binSize);
125  double min_t = -nBinsNeg * binSize - halfBinSize; // lower edge value of left most bin
126  int nbins = nBinsNeg * 2 + 1; // number of negative time bins + t=0 bin + number of positive time bins
127  double max_t = min_t + nbins * binSize; // upper edge value of right most bin
128 
129  /* Variable bin width information for the time information vs energy since
130  the time width should vary as a function of 1/E */
131  const Int_t N_E_BIN_EDGES = 64;
132  const Int_t N_E_BINS = N_E_BIN_EDGES - 1;
133  Double_t energyBinEdges[N_E_BIN_EDGES] = {0, 0.05, 0.051, 0.052, 0.053, 0.054, 0.055, 0.056, 0.057, 0.058, 0.059, 0.06, 0.062, 0.064, 0.066, 0.068, 0.07, 0.075, 0.08, 0.085, 0.09, 0.095, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.25, 0.3, 0.35, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8, 2, 2.25, 2.5, 2.8, 3.2, 3.6, 4, 4.4, 4.8, 5.2, 5.6, 6, 6.4, 6.8, 7.2, 7.6, 8};
134 
135 
136  auto cutflow = new TH1F("cutflow", " ;Cut label number ;Number of events passing cut", 10, 0, 10) ;
137  registerObject<TH1F>("cutflow", cutflow) ;
138 
139  auto clusterTime = new TH1F("clusterTime", ";Photon ECL cluster time [ns]; number of photon ECL clusters", nbins, min_t, max_t) ;
140  registerObject<TH1F>("clusterTime", clusterTime) ;
141 
142  auto clusterTime_cid = new TH2F("clusterTime_cid",
143  ";crystal Cell ID ;Photon ECL cluster time [ns]", 8736, 1, 8736 + 1, nbins, min_t, max_t) ;
144  registerObject<TH2F>("clusterTime_cid", clusterTime_cid) ;
145 
146  auto clusterTime_run = new TH2F("clusterTime_run",
147  ";Run number ;Photon ECL cluster time [ns]", 7000, 0, 7000, nbins, min_t, max_t) ;
148  registerObject<TH2F>("clusterTime_run", clusterTime_run) ;
149 
150 
151  auto clusterTimeClusterE = new TH2F("clusterTimeClusterE",
152  ";Photon cluster energy [GeV];Photon cluster time [ns]", N_E_BINS, energyBinEdges, nbins, min_t, max_t) ;
153  registerObject<TH2F>("clusterTimeClusterE", clusterTimeClusterE) ;
154 
155 
156  auto dt99_clusterE = new TH2F("dt99_clusterE",
157  ";Photon cluster energy [GeV];dt99 [ns]", N_E_BINS, energyBinEdges, nbins, 0, max_t) ;
158  registerObject<TH2F>("dt99_clusterE", dt99_clusterE) ;
159 
160 
161  auto eventT0 = new TH1F("eventT0", ";event t0 [ns]; number of events", nbins, min_t, max_t) ;
162  registerObject<TH1F>("eventT0", eventT0) ;
163 
164 
165  auto clusterTimeE0E1diff = new TH1F("clusterTimeE0E1diff",
166  ";ECL cluster time of max E photon - ECL cluster time of 2nd max E photon [ns]; number of photon ECL cluster time differences",
167  nbins, min_t, max_t) ;
168  registerObject<TH1F>("clusterTimeE0E1diff", clusterTimeE0E1diff) ;
169 
170 
171  //=== Required data objects
172  tracks.isRequired() ;
173  m_eclClusterArray.isRequired() ;
174  m_eclCalDigitArray.isRequired() ;
175 
176 }
177 
179 {
180  int cutIndexPassed = 0;
181  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
182  B2DEBUG(22, "Cutflow: no cuts: index = " << cutIndexPassed);
183 
184 
185 
186  // Storage crystal energies
187  m_EperCrys.resize(8736);
188  for (auto& eclCalDigit : m_eclCalDigitArray) {
189  int tempCrysID = eclCalDigit.getCellId() - 1;
190  m_EperCrys[tempCrysID] = eclCalDigit.getEnergy();
191  }
192 
193  // Getting the event t0 using the full event t0 rather than from the CDC specifically
194 
195  double evt_t0 = -1000 ;
196  double evt_t0_unc = -1000 ;
197 
198  // Determine if there is an event t0 to use and then extract the information about it
199  if (m_eventT0.isOptional()) {
200  if (!m_eventT0.isValid()) {
201  return;
202  }
203  if (!m_eventT0->hasEventT0()) {
204  return;
205  } else {
206  // Overall event t0 (combination of multiple event t0s from different detectors)
207  evt_t0 = m_eventT0->getEventT0() ;
208  evt_t0_unc = m_eventT0->getEventT0Uncertainty() ;
209  }
210  B2DEBUG(26, "Found event t0") ;
211  }
212 
213  //---------------------------------------------------------------------
214  //..Track properties. Use pion (211) mass hypothesis,
215  // which is the only particle hypothesis currently available???
216  int nTrkAll = tracks.getEntries() ;
217 
218  int nTrkLoose = 0 ;
219  int nTrkTight = 0 ;
222  /* Loop over all the tracks to define the tight and loose selection tracks.
223  We will select events with only a few tight tracks and no additional loose tracks.
224  Tight tracks are a subset of looses tracks. */
225  for (int iTrk = 0 ; iTrk < nTrkAll ; iTrk++) {
226 
227  // Get track biasing towards the particle being a pion
228  const TrackFitResult* tempTrackFit = tracks[iTrk]->getTrackFitResultWithClosestMass(Const::pion) ;
229  if (not tempTrackFit) {continue ;}
230 
231  // Collect track info to be used for categorizing
232  //short charge = tempTrackFit->getChargeSign() ;
233  double z0 = tempTrackFit->getZ0() ;
234  double d0 = tempTrackFit->getD0() ;
235  int nCDChits = tempTrackFit->getHitPatternCDC().getNHits() ;
236  //double pt = tempTrackFit->getTransverseMomentum() ;
237  //double p = tempTrackFit->getMomentum().Mag() ;
238 
239  /* Test if loose track */
240 
241  // d0 and z0 cuts
242  if (fabs(d0) > m_looseTrkD0) {
243  continue;
244  }
245  if (fabs(z0) > m_looseTrkZ0) {
246  continue;
247  }
248  // Number of hits in the CDC
249  if (nCDChits < 1) {
250  continue;
251  }
252  nTrkLoose++;
253 
254 
255 
256  /* Test if the loose track is also a tight track */
257 
258  // Number of hits in the CDC
259  if (nCDChits < 20) {
260  continue;
261  }
262  // d0 and z0 cuts
263  if (fabs(d0) > m_tightTrkD0) {
264  continue;
265  }
266  if (fabs(z0) > m_tightTrkZ0) {
267  continue;
268  }
269  nTrkTight++;
270 
271  }
272  // After that last section the numbers of loose and tight tracks are known
273  B2DEBUG(26, "Found loose and tight tracks") ;
274 
275 
276  int numGoodTightTracks_minCut = 4 ;
277  if (nTrkTight < numGoodTightTracks_minCut) {
278  return ;
279  }
280  // There are at least X tight tracks
281  cutIndexPassed++ ;
282  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed) ;
283  B2DEBUG(22, "Cutflow: At least " << numGoodTightTracks_minCut << " tight tracks: index = " << cutIndexPassed) ;
284 
285 
286  int numGoodLooseTracks_minCut = numGoodTightTracks_minCut ;
287  if (nTrkLoose < numGoodLooseTracks_minCut) {
288  return ;
289  }
290  // There are more loose tracks than tight tracks then veto the event. If there are fewer loose tracks than tight tracks then veto the event, although this should be impossible
291  cutIndexPassed++ ;
292  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed) ;
293  B2DEBUG(22, "Cutflow: No additional loose tracks: index = " << cutIndexPassed) ;
294 
295 
296  //------------------------------------------------------------------------
297  // Find the good ECL clusters
298  double clusterE_minCut = 0.1 ; // GeV
299  int nclust = m_eclClusterArray.getEntries();
300  int nGoodClusts = 0 ;
301  vector<int> goodClusterIdxs ;
302  for (int ic = 0; ic < nclust; ic++) {
303  double eClust = m_eclClusterArray[ic]->getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons) ;
304  if (eClust > clusterE_minCut) {
305  goodClusterIdxs.push_back(ic) ;
306  nGoodClusts++ ;
307  }
308  }
309 
310 
311  // Cut on the minimum number of good clusters
312  int numGoodEMclusters_minCut = 5 ;
313  if (nGoodClusts < numGoodEMclusters_minCut) {
314  return ;
315  }
316  // There are at least 5 good EM clusters (photon = basically all clusters)
317  cutIndexPassed++ ;
318  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed) ;
319  B2DEBUG(22, "Cutflow: At least " << numGoodEMclusters_minCut << " ECL clusters: index = " << cutIndexPassed) ;
320 
321 
322  //------------------------------------------------------------------------
323  // Find the good photons first before doing anything with them
324 
325  double photonE_minCut = 0.05 ; // GeV
326  double zernikeMVA_minCut = 0.2 ;
327  int nPhotons = 0 ;
328 
329  vector<int> goodPhotonClusterIdxs ;
330  for (int ic = 0; ic < nclust; ic++) {
331  if (m_eclClusterArray[ic]->hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons)) {
332  double eClust = m_eclClusterArray[ic]->getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons);
333  double photonTime = m_eclClusterArray[ic]->getTime();
334  double zernikeMVA = m_eclClusterArray[ic]->getZernikeMVA();
335  bool badPhotonTime = m_eclClusterArray[ic]->hasFailedFitTime();
336  bool badPhotonTimeResolution = m_eclClusterArray[ic]->hasFailedTimeResolution();
337  bool hasTrack = m_eclClusterArray[ic]->isTrack();
338  if ((eClust > photonE_minCut) &&
339  (fabs(photonTime) < m_timeAbsMax) &&
340  (!badPhotonTime) &&
341  (!badPhotonTimeResolution) &&
342  (zernikeMVA > zernikeMVA_minCut) &&
343  (!hasTrack)) {
344  goodPhotonClusterIdxs.push_back(ic) ;
345  nPhotons++;
346  }
347  }
348  }
349 
350 
351  // Cut on the minimum number of good photon clusters
352  int numGoodPhotonclusters_minCut = 1 ;
353  if (nPhotons < numGoodPhotonclusters_minCut) {
354  return ;
355  }
356  // There is at least one good photon in the event
357  cutIndexPassed++ ;
358  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed) ;
359  B2DEBUG(22, "Cutflow: At least " << numGoodPhotonclusters_minCut << " good photon: index = " << cutIndexPassed) ;
360 
361 
362 
363  //------------------------------------------------------------------------
364  /* Extract the times of the good clusters and
365  save the maximum energy crystal information (cid) */
366  vector<double> goodClustTimes ;
367  vector<double> goodClust_dt99 ;
368  vector<double> goodClusters_crysE ;
369  vector<double> goodClustE ;
370  vector<int> goodClustMaxEcrys_cid ;
371  for (long unsigned int i = 0; i < goodPhotonClusterIdxs.size(); i++) {
372  int ic = goodPhotonClusterIdxs[i] ;
373 
374  if (m_eclClusterArray[ic]->hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons)) {
375  double eClust = m_eclClusterArray[ic]->getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons);
376  short cid = m_eclClusterArray[ic]->getMaxECellId() ;
377 
378  goodClustMaxEcrys_cid.push_back(cid) ;
379  goodClustTimes.push_back(m_eclClusterArray[ic]->getTime()) ;
380  goodClust_dt99.push_back(m_eclClusterArray[ic]->getDeltaTime99()) ;
381  goodClusters_crysE.push_back(m_EperCrys[cid - 1]) ;
382  goodClustE.push_back(eClust);
383  }
384  }
385 
386 
387  // Define a pair (energy,time) so that we can quickly and easily sort the cluster information
388  // based on the energy of the clusters
389  vector< pair<double, double> > pair_energy_time ;
390  for (long unsigned int ic = 0; ic < goodClusters_crysE.size(); ic++) {
391  pair_energy_time.push_back(make_pair(goodClusters_crysE[ic], goodClustTimes[ic])) ;
392  }
393 
394  // sorts pairs in decreasing order of their first value (energy)
395  // i.e. highest energy first
396  sort(pair_energy_time.begin(), pair_energy_time.end(), greater<>()) ;
397 
398 
399 
400  B2DEBUG(22, "Event passed all cuts");
401 
402 
403  // Fill the histogram for the event level variables
404  getObjectPtr<TH1F>("eventT0")->Fill(evt_t0) ;
405 
406  bool isCDCt0 = (static_cast<EventT0::EventT0Component>(*m_eventT0->getEventT0Component())).detectorSet.contains(Const::CDC);
407  bool isECLt0 = (static_cast<EventT0::EventT0Component>(*m_eventT0->getEventT0Component())).detectorSet.contains(Const::ECL);
408  string t0Detector = "UNKNOWN... WHY?";
409  if (isCDCt0) {
410  t0Detector = "CDC" ;
411  } else if (isECLt0) {
412  t0Detector = "ECL" ;
413  }
414 
415  B2DEBUG(26, "t0 = " << evt_t0 << " ns. t0 is from CDC?=" << isCDCt0 << ", t0 is from ECL?=" << isECLt0 << " t0 from " <<
416  t0Detector);
417 
418 
419 
420  //=== For each good photon cluster in the processed event and fill histogram.
421 
422  StoreObjPtr<EventMetaData> evtMetaData ;
423  for (long unsigned int i = 0 ; i < goodPhotonClusterIdxs.size() ; i++) {
424  getObjectPtr<TH1F>("clusterTime")->Fill(goodClustTimes[i]) ;
425  getObjectPtr<TH2F>("clusterTime_cid")->Fill(goodClustMaxEcrys_cid[i] + 0.001, goodClustTimes[i] , 1) ;
426  getObjectPtr<TH2F>("clusterTime_run")->Fill(evtMetaData->getRun() + 0.001, goodClustTimes[i] , 1) ;
427  getObjectPtr<TH2F>("clusterTimeClusterE")->Fill(goodClustE[i], goodClustTimes[i], 1) ;
428  getObjectPtr<TH2F>("dt99_clusterE")->Fill(goodClustE[i], goodClust_dt99[i], 1) ;
429 
430  //== Save debug TTree with detailed information if necessary.
431  if (m_saveTree) {
432 
433  m_tree_time = goodClustTimes[i] ;
434  m_E_photon_clust = goodClusters_crysE[i] ;
435  m_tree_t0 = evt_t0 ;
436  m_tree_t0_unc = evt_t0_unc ;
437  m_NtightTracks = nTrkTight ;
438  m_NphotonClusters = nPhotons ;
439  m_NGoodClusters = nGoodClusts ;
440  m_tree_evt_num = evtMetaData->getEvent() ;
441  m_tree_run = evtMetaData->getRun() ;
442  m_tree_cid = goodClustMaxEcrys_cid[i] ;
443  m_tree_dt99 = goodClust_dt99[i] ;
444 
445  m_dbg_tree_photonClusters->Fill() ;
446 
447  }
448  }
449  B2DEBUG(26, "Filled cluster tree") ;
450 
451  //=== Fill histogram for cluster time difference of the two max E photons
452  if (pair_energy_time.size() >= 2) {
453  getObjectPtr<TH1F>("clusterTimeE0E1diff")->Fill(pair_energy_time[0].second - pair_energy_time[1].second) ;
454  }
455 
456 
457 
458  if (m_saveTree) {
459  m_tree_t0 = evt_t0 ;
460  m_tree_t0_unc = evt_t0_unc ;
461  m_tree_evt_num = evtMetaData->getEvent() ;
462  m_tree_run = evtMetaData->getRun() ;
463  m_NtightTracks = nTrkTight ;
464  m_NphotonClusters = nPhotons ;
465  m_NGoodClusters = nGoodClusts ;
466 
467  m_tree_E0 = pair_energy_time[0].first ;
468  m_tree_time_fromE0 = pair_energy_time[0].second ;
469  m_dbg_tree_event->Fill() ;
470  }
471 
472  B2DEBUG(26, "Filled event tree") ;
473 
474 }
Calibration collector module base class.
static const ChargedStable pion
charged pion particle
Definition: Const.h:542
@ c_nPhotons
CR is split into n photons (N1)
unsigned short getNHits() const
Get the total Number of CDC hits in the fit.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
Values of the result of a track fit with a given particle hypothesis.
double getD0() const
Getter for d0.
double getZ0() const
Getter for z0.
HitPatternCDC getHitPatternCDC() const
Getter for the hit pattern in the CDC;.
This module generates 'TimevsCrys' histogram to later (in eclBhabhaTAlgorithm) find time offset from ...
void collect() override
Select events and crystals and accumulate histograms.
void inDefineHisto() override
Replacement for defineHisto() in CalibrationCollector modules.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
Structure for storing the extracted event t0s together with its detector and its uncertainty.
Definition: EventT0.h:34