Belle II Software  release-06-02-00
ECLBhabhaTCollectorModule.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 #include <ecl/modules/eclBhabhaTCollector/ECLBhabhaTCollectorModule.h>
10 #include <framework/dataobjects/EventMetaData.h>
11 #include <framework/gearbox/Const.h>
12 #include <ecl/dbobjects/ECLCrystalCalib.h>
13 #include <ecl/dbobjects/ECLReferenceCrystalPerCrateCalib.h>
14 #include <ecl/dataobjects/ECLDigit.h>
15 #include <ecl/dataobjects/ECLCalDigit.h>
16 #include <mdst/dataobjects/ECLCluster.h>
17 #include <mdst/dataobjects/Track.h>
18 #include <mdst/dataobjects/HitPatternCDC.h>
19 #include <tracking/dataobjects/RecoTrack.h>
20 #include <ecl/digitization/EclConfiguration.h>
21 #include <analysis/utility/PCmsLabTransform.h>
22 #include <analysis/ClusterUtility/ClusterUtils.h>
23 #include <boost/optional.hpp>
24 #include <ecl/geometry/ECLGeometryPar.h>
25 
26 #include <TH2F.h>
27 #include <TTree.h>
28 #include <TFile.h>
29 
30 using namespace Belle2;
31 using namespace ECL;
32 using namespace std;
33 
34 //-----------------------------------------------------------------
35 // Register the Module
36 //-----------------------------------------------------------------
37 REG_MODULE(ECLBhabhaTCollector)
38 
39 //-----------------------------------------------------------------
40 // Implementation
41 //-----------------------------------------------------------------
42 
44  m_ElectronicsDB("ECLCrystalElectronics"),
45  m_ElectronicsTimeDB("ECLCrystalElectronicsTime"),
46  m_FlightTimeDB("ECLCrystalFlightTime"),
47  m_PreviousCrystalTimeDB("ECLCrystalTimeOffset"),
48  m_CrateTimeDB("ECLCrateTimeOffset"),
49  m_RefCrystalsCalibDB("ECLReferenceCrystalPerCrateCalib"),
50  m_channelMapDB("ECLChannelMap")//,
51 {
52  setDescription("This module generates sum of all event times per crystal");
53 
54  addParam("timeAbsMax", m_timeAbsMax, // (Time in ns)
55  "Events with fabs(getTimeFit) > m_timeAbsMax "
56  "are excluded", (short)80);
57 
58  addParam("minCrystal", m_minCrystal,
59  "First CellId to handle.", 1);
60  addParam("maxCrystal", m_maxCrystal,
61  "Last CellId to handle.", 8736);
62 
63  addParam("saveTree", m_saveTree,
64  "If true, TTree 'tree' with more detailed event info is saved in "
65  "the output file specified by HistoManager",
66  false);
67 
68  addParam("looseTrkZ0", m_looseTrkZ0, "max Z0 for loose tracks (cm)", 10.);
69  addParam("tightTrkZ0", m_tightTrkZ0, "max Z0 for tight tracks (cm)", 2.);
70  addParam("looseTrkD0", m_looseTrkD0, "max D0 for loose tracks (cm)", 2.);
71  addParam("tightTrkD0", m_tightTrkD0, "max D0 for tight tracks (cm)", 0.5); // beam pipe radius = 1cm in 2019
72  addParam("skipTrgSel", skipTrgSel, "boolean to skip the trigger skim selection", false);
73 
74  addParam("hadronEventT0_TO_bhabhaEventT0_correction", m_hadronEventT0_TO_bhabhaEventT0_correction,
75  "CDC bhabha t0 bias correction (ns)", 0.);
76 
77  // specify this flag if you need parallel processing
78  setPropertyFlags(c_ParallelProcessingCertified);
79 }
80 
82 {
83 }
84 
86 {
87  //=== Prepare TTree for debug output
88  if (m_saveTree) { // /* >>>>>>>>>>>>>>>>>>>>>>>>>>>> if boolean true for saving debug trees >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
89  // Per electron
90  m_dbgTree_electrons = new TTree("tree_electrons", "Debug data for bhabha time calibration - one entry per electron");
91  m_dbgTree_electrons->Branch("EventNum", &m_tree_evtNum)->SetTitle("Event number");
92  m_dbgTree_electrons->Branch("CrystalCellID", &m_tree_cid)->SetTitle("Cell ID, 1..8736");
93  m_dbgTree_electrons->Branch("ADCamplitude", &m_tree_amp)->SetTitle("Amplitude, ADC units");
94  m_dbgTree_electrons->Branch("maxEcrystalEnergy", &m_tree_en)->SetTitle("Max Energy Crystal Energy, GeV");
95  m_dbgTree_electrons->Branch("maxEcrystalEnergyDIVclusterE",
96  &m_tree_E1Etot)->SetTitle("Max Energy Crystal Fraction Energy of Cluster");
97  m_dbgTree_electrons->Branch("E1divE2crystal",
98  &m_tree_E1E2)->SetTitle("Max Energy Crystal DIV second max energy crystal in cluster");
99  m_dbgTree_electrons->Branch("E1crystal_DIV_p", &m_tree_E1p)->SetTitle("Max Energy Crystal in cluster DIV track p");
100  m_dbgTree_electrons->Branch("timetsPreviousTimeCalibs",
101  &m_tree_timetsPreviousTimeCalibs)->SetTitle("Time t_psi after application of previous Ts, ns");
102  m_dbgTree_electrons->Branch("E_DIV_p", &m_E_DIV_p)->SetTitle("E DIV p");
103  m_dbgTree_electrons->Branch("timeF", &m_tree_timeF)->SetTitle("Time F, ns");
104  m_dbgTree_electrons->Branch("time_t_psi", &m_tree_time)->SetTitle("Time t_psi for Ts, ns");
105  m_dbgTree_electrons->Branch("quality", &m_tree_quality)->SetTitle("ECL FPGA fit quality, see Confluence article");
106  m_dbgTree_electrons->Branch("t0", &m_tree_t0)->SetTitle("T0, ns");
107  m_dbgTree_electrons->Branch("t0_unc", &m_tree_t0_unc)->SetTitle("T0 uncertainty, ns");
108  m_dbgTree_electrons->Branch("CrateID", &m_crystalCrate)->SetTitle("Crate id for crystal");
109  m_dbgTree_electrons->Branch("runNum", &m_runNum)->SetTitle("Run number");
110 
111  m_dbgTree_electrons->SetAutoSave(10);
112 
113 
114  // Per track
115  m_dbgTree_tracks = new TTree("tree_tracks", "Debug data for bhabha time calibration - one entry per track");
116  m_dbgTree_tracks->Branch("d0", &m_tree_d0)->SetTitle("d0, cm");
117  m_dbgTree_tracks->Branch("z0", &m_tree_z0)->SetTitle("z0, cm");
118  m_dbgTree_tracks->Branch("p", &m_tree_p)->SetTitle("track momentum, GeV");
119  m_dbgTree_tracks->Branch("charge", &m_charge)->SetTitle("track electric charge");
120  m_dbgTree_tracks->Branch("Num_CDC_hits", &m_tree_nCDChits)->SetTitle("Num CDC hits");
121 
122  m_dbgTree_tracks->SetAutoSave(10);
123 
124  // Per crystal
125  m_dbgTree_crystals = new TTree("tree_crystals",
126  "Debug data for bhabha time calibration - one entry per electron - one entry per crystal");
127  m_dbgTree_crystals->Branch("clustCrysE_DIV_maxEcrys",
128  &m_tree_clustCrysE_DIV_maxEcrys)->SetTitle("E of crystal i from cluster / E of max E crystal");
129  m_dbgTree_crystals->Branch("Crystal_E", &m_tree_clustCrysE) ->SetTitle("E of crystal i from cluster");
130  m_dbgTree_crystals->Branch("time_t_psi", &m_tree_time)->SetTitle("Time for Ts, ns");
131  m_dbgTree_crystals->Branch("Crystal_cell_ID", &m_tree_cid)->SetTitle("Cell ID, 1..8736");
132  m_dbgTree_crystals->Branch("quality", &m_tree_quality)->SetTitle("ECL FPGA fit quality, see Confluence article");
133 
134  m_dbgTree_crystals->SetAutoSave(10);
135 
136 
137  // Per event
138  m_dbgTree_event = new TTree("tree_event", "Debug data for bhabha time calibration - one entry per event");
139  m_dbgTree_event->Branch("massInvTracks", &m_massInvTracks)->SetTitle("Invariant mass of the two tracks");
140 
141  m_dbgTree_event->SetAutoSave(10);
142 
143 
144  m_dbgTree_evt_allCuts = new TTree("tree_evt_allCuts",
145  "Debug data for bhabha time calibration - one entry per event after all the cuts");
146  m_dbgTree_evt_allCuts->Branch("EclustPlus", &m_tree_enPlus)->SetTitle("Energy of cluster with +ve charge, GeV");
147  m_dbgTree_evt_allCuts->Branch("EclustNeg", &m_tree_enNeg)->SetTitle("Energy of cluster with -ve charge, GeV");
148  m_dbgTree_evt_allCuts->Branch("clustTimePos", &m_tree_tClustPos)->SetTitle("Cluster time of cluster with +ve charge, GeV");
149  m_dbgTree_evt_allCuts->Branch("clustTimeNeg", &m_tree_tClustNeg)->SetTitle("Cluster time of cluster with -ve charge, GeV");
150  m_dbgTree_evt_allCuts->Branch("maxEcrysTimePosClust",
151  &m_tree_maxEcrystPosClust)->SetTitle("Time of maximum energy crystal in cluster with +ve charge, GeV");
152  m_dbgTree_evt_allCuts->Branch("maxEcrysTimeNegClust",
153  &m_tree_maxEcrystNegClust)->SetTitle("Time of maximum energy crystal in cluster with -ve charge, GeV");
154  m_dbgTree_evt_allCuts->Branch("t0", &m_tree_t0)->SetTitle("T0, ns");
155  m_dbgTree_evt_allCuts->Branch("t0_ECL_closestCDC", &m_tree_t0_ECLclosestCDC)->SetTitle("T0 ECL closest to CDC t0, ns");
156  m_dbgTree_evt_allCuts->Branch("t0_ECL_minChi2", &m_tree_t0_ECL_minChi2)->SetTitle("T0 ECL with smallest chi squared, ns");
157 
158  m_dbgTree_evt_allCuts->SetAutoSave(10);
159 
160 
161  // Per crystal within each cluster, entry after all the cuts
162  m_dbgTree_crys_allCuts = new TTree("m_dbgTree_crys_allCuts",
163  "Debug data for bhabha time calibration - one entry per crystal per cluster entry after all cuts");
164 
165  m_dbgTree_crys_allCuts->Branch("runNum", &m_runNum)->SetTitle("Run number");
166  m_dbgTree_crys_allCuts->Branch("EventNum", &m_tree_evtNum)->SetTitle("Event number");
167  m_dbgTree_crys_allCuts->Branch("m_tree_ECLCalDigitTime",
168  &m_tree_ECLCalDigitTime)
169  ->SetTitle("Time of a crystal within the cluster after application of previous calibrations except t0, ns");
170  m_dbgTree_crys_allCuts->Branch("m_tree_ECLCalDigitE", &m_tree_ECLCalDigitE)->SetTitle("Energy of crystal, GeV");
171  m_dbgTree_crys_allCuts->Branch("m_tree_ECLDigitAmplitude",
172  &m_tree_ECLDigitAmplitude)->SetTitle("Amplitude of crystal signal pulse");
173  m_dbgTree_crys_allCuts->Branch("timetsPreviousTimeCalibs",
174  &m_tree_timetsPreviousTimeCalibs)->SetTitle("Time t_psi after application of previous Ts, ns");
175  m_dbgTree_crys_allCuts->Branch("t0", &m_tree_t0)->SetTitle("T0, ns");
176  m_dbgTree_crys_allCuts->Branch("t0_ECL_closestCDC", &m_tree_t0_ECLclosestCDC)->SetTitle("T0 ECL closest to CDC t0, ns");
177  m_dbgTree_crys_allCuts->Branch("t0_ECL_minChi2", &m_tree_t0_ECL_minChi2)->SetTitle("T0 ECL with smallest chi squared, ns");
178  m_dbgTree_crys_allCuts->Branch("CrystalCellID", &m_tree_cid)->SetTitle("Cell ID, 1..8736");
179 
180  m_dbgTree_crys_allCuts->SetAutoSave(10);
181 
182 
183  } // <<<<<<<<<<<<<<<<<<<<< if boolean true for saving debug trees <<<<<<<<<<<<<<<<<<<<<<<<<< */
184 
185 
186  // Per max E crystal entry after all the cuts
187  // this tree is always saved
188  m_dbgTree_allCuts = new TTree("tree_allCuts",
189  "Debug data for bhabha time calibration - one entry per max E crystal entry after cuts");
190 
191  m_dbgTree_allCuts->Branch("time_t_psi", &m_tree_time)->SetTitle("Time t_psi for Ts, ns");
192  m_dbgTree_allCuts->Branch("crateID", &m_crystalCrate)->SetTitle("Crate id for crystal");
193  m_dbgTree_allCuts->Branch("EventNum", &m_tree_evtNum)->SetTitle("Event number");
194  m_dbgTree_allCuts->Branch("runNum", &m_runNum)->SetTitle("Run number");
195  m_dbgTree_allCuts->Branch("CrystalCellID", &m_tree_cid)->SetTitle("Cell ID, 1..8736");
196  m_dbgTree_allCuts->Branch("maxEcrystalEnergy", &m_tree_en)->SetTitle("Max Energy Crystal Energy, GeV");
197  m_dbgTree_allCuts->Branch("maxEcrystalEnergyDIVclusterE",
198  &m_tree_E1Etot)->SetTitle("Max Energy Crystal Fraction Energy of Cluster");
199  m_dbgTree_allCuts->Branch("E1divE2crystal",
200  &m_tree_E1E2)->SetTitle("Max Energy Crystal DIV second max energy crystal in cluster");
201  m_dbgTree_allCuts->Branch("E1crystalDIVp", &m_tree_E1p)->SetTitle("Max Energy Crystal in cluster DIV track p");
202  m_dbgTree_allCuts->Branch("timetsPreviousTimeCalibs",
203  &m_tree_timetsPreviousTimeCalibs)->SetTitle("Time t_psi after application of previous Ts, ns");
204  m_dbgTree_allCuts->Branch("massInvTracks", &m_massInvTracks)->SetTitle("Invariant mass of the two tracks");
205  m_dbgTree_allCuts->Branch("t0", &m_tree_t0)->SetTitle("T0, ns");
206  m_dbgTree_allCuts->Branch("t0_ECL_closestCDC", &m_tree_t0_ECLclosestCDC)->SetTitle("T0 ECL closest to CDC t0, ns");
207  m_dbgTree_allCuts->Branch("t0_ECL_minChi2", &m_tree_t0_ECL_minChi2)->SetTitle("T0 ECL with smallest chi squared, ns");
208 
209  m_dbgTree_allCuts->Branch("clusterTime", &m_tree_tClust)->SetTitle("Cluster time of cluster with +ve charge, GeV");
210 
211  m_dbgTree_allCuts->SetAutoSave(10);
212 
213 }
214 
216 {
217  //=== MetaData
218  B2INFO("ECLBhabhaTCollector: Experiment = " << m_EventMetaData->getExperiment() <<
219  " run = " << m_EventMetaData->getRun());
220 
221 
222  //=== Create histograms and register them in the data store
223  int nbins = m_timeAbsMax * 8;
224  int max_t = m_timeAbsMax;
225  int min_t = -m_timeAbsMax;
226 
227 
228  auto TimevsCrysPrevCrateCalibPrevCrystCalib = new TH2F("TimevsCrysPrevCrateCalibPrevCrystCalib",
229  "Time t psi - ts - tcrate (previous calibs) vs crystal cell ID;crystal cell ID;Time t_psi with previous calib (ns)",
230  8736, 1, 8736 + 1, nbins, min_t, max_t);
231  registerObject<TH2F>("TimevsCrysPrevCrateCalibPrevCrystCalib", TimevsCrysPrevCrateCalibPrevCrystCalib);
232 
233  auto TimevsCratePrevCrateCalibPrevCrystCalib = new TH2F("TimevsCratePrevCrateCalibPrevCrystCalib",
234  "Time t psi - ts - tcrate (previous calibs) vs crate ID;crate ID;Time t_psi previous calib (ns)",
235  52, 1, 52 + 1, nbins, min_t, max_t);
236  registerObject<TH2F>("TimevsCratePrevCrateCalibPrevCrystCalib", TimevsCratePrevCrateCalibPrevCrystCalib);
237 
238  auto TimevsCrysNoCalibrations = new TH2F("TimevsCrysNoCalibrations",
239  "Time tpsi vs crystal cell ID;crystal cell ID;Time t_psi (ns)", 8736, 1, 8736 + 1, nbins, min_t, max_t);
240  registerObject<TH2F>("TimevsCrysNoCalibrations", TimevsCrysNoCalibrations);
241 
242  auto TimevsCrateNoCalibrations = new TH2F("TimevsCrateNoCalibrations",
243  "Time tpsi vs crate ID;crate ID;Time t_psi (ns)", 52, 1, 52 + 1, nbins, min_t, max_t);
244  registerObject<TH2F>("TimevsCrateNoCalibrations", TimevsCrateNoCalibrations);
245 
246  auto TimevsCrysPrevCrateCalibNoCrystCalib = new TH2F("TimevsCrysPrevCrateCalibNoCrystCalib",
247  "Time tpsi - tcrate (previous calib) vs crystal cell ID;crystal cell ID;Time t_psi including previous crate calib (ns)",
248  8736, 1, 8736 + 1, nbins, min_t, max_t);
249  registerObject<TH2F>("TimevsCrysPrevCrateCalibNoCrystCalib", TimevsCrysPrevCrateCalibNoCrystCalib);
250 
251  auto TimevsCrateNoCrateCalibPrevCrystCalib = new TH2F("TimevsCrateNoCrateCalibPrevCrystCalib",
252  "Time tpsi - ts (previous calib) vs crate ID;crate ID;Time t_psi including previous crystal calib (ns)",
253  52, 1, 52 + 1, nbins, min_t, max_t);
254  registerObject<TH2F>("TimevsCrateNoCrateCalibPrevCrystCalib", TimevsCrateNoCrateCalibPrevCrystCalib);
255 
256 
257  auto TsDatabase = new TH1F("TsDatabase", ";cell id;Ts from database", 8736, 1, 8736 + 1);
258  registerObject<TH1F>("TsDatabase", TsDatabase);
259 
260  auto TsDatabaseUnc = new TH1F("TsDatabaseUnc", ";cell id;Ts uncertainty from database", 8736, 1, 8736 + 1);
261  registerObject<TH1F>("TsDatabaseUnc", TsDatabaseUnc);
262 
263  auto TcrateDatabase = new TH1F("TcrateDatabase", ";cell id;Tcrate from database", 8736, 1, 8736 + 1);
264  registerObject<TH1F>("TcrateDatabase", TcrateDatabase);
265 
266  auto TcrateUncDatabase = new TH1F("TcrateUncDatabase", ";cell id;Tcrate uncertainty from database", 8736, 1, 8736 + 1);
267  registerObject<TH1F>("TcrateUncDatabase", TcrateUncDatabase);
268 
269 
270  auto tcrateDatabase_ns = new TH1F("tcrateDatabase_ns", ";crate id;tcrate derived from database", 52, 1, 52 + 1);
271  registerObject<TH1F>("tcrateDatabase_ns", tcrateDatabase_ns);
272 
273 
274  auto databaseCounter = new TH1I("databaseCounter",
275  ";A database was read in;Number of times database was saved to histogram", 1, 1, 2);
276  registerObject<TH1I>("databaseCounter", databaseCounter);
277 
278 
279  auto numCrystalEntriesPerEvent = new TH1F("numCrystalEntriesPerEvent",
280  ";Number crystal entries;Number of events", 15, 0, 15);
281  registerObject<TH1F>("numCrystalEntriesPerEvent", numCrystalEntriesPerEvent);
282 
283  auto cutflow = new TH1F("cutflow", ";Cut label number;Number of events passing cut", 20, 0, 20);
284  registerObject<TH1F>("cutflow", cutflow);
285 
286  auto maxEcrsytalEnergyFraction = new TH1F("maxEcrsytalEnergyFraction",
287  ";Maximum energy crystal energy / (sum) cluster energy;Number", 22, 0, 1.1);
288  registerObject<TH1F>("maxEcrsytalEnergyFraction", maxEcrsytalEnergyFraction);
289 
290  auto refCrysIDzeroingCrate = new TH1F("refCrysIDzeroingCrate", ";cell id;Boolean - is reference crystal", 8736, 1, 8736 + 1);
291  registerObject<TH1F>("refCrysIDzeroingCrate", refCrysIDzeroingCrate);
292 
293  auto CDCEventT0Correction = new TH1F("CDCEventT0Correction", ";;CDC event t0 offset correction [ns]", 1, 1, 2);
294  registerObject<TH1F>("CDCEventT0Correction", CDCEventT0Correction);
295 
296 
297  //=== Required data objects
298  m_eventT0.isRequired();
299  tracks.isRequired();
300  m_eclClusterArray.isRequired();
301  m_eclCalDigitArray.isRequired();
302  m_eclDigitArray.isRequired();
303 
304  B2INFO("hadronEventT0_TO_bhabhaEventT0_correction = " << m_hadronEventT0_TO_bhabhaEventT0_correction <<
305  " ns correction to CDC event t0 will be applied");
306 
307  B2INFO("skipTrgSel = " << skipTrgSel);
308 
309 }
310 
312 {
313  int cutIndexPassed = 0;
314  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
315  B2DEBUG(22, "Cutflow: no cuts: index = " << cutIndexPassed);
316  B2DEBUG(22, "Event number = " << m_EventMetaData->getEvent());
317 
318 
319  // --- Check the trigger skim is the type that has two tracks
320 
321  /* If we skip the trigger skim selection then still fill the cutflow histogram
322  just so that the positions don't change. */
323  if (!skipTrgSel) {
324  if (!m_TrgResult.isValid()) {
325  B2WARNING("SoftwareTriggerResult required to select bhabha event is not found");
326  return;
327  }
328 
329  /* Release05: bhabha_all is grand skim = bhabha+bhabhaecl+radee. We only want
330  to look at the 2 track bhabha events. */
331  const std::map<std::string, int>& fresults = m_TrgResult->getResults();
332  if (fresults.find("software_trigger_cut&skim&accept_bhabha") == fresults.end()) {
333  B2WARNING("Can't find required bhabha trigger identifier");
334  return;
335  }
336 
337  const bool eBhabha = (m_TrgResult->getResult("software_trigger_cut&skim&accept_bhabha") ==
339  B2DEBUG(22, "eBhabha (trigger passed) = " << eBhabha);
340 
341  if (!eBhabha) {
342  return;
343  }
344  }
345 
346  /* Fill the histgram showing that the trigger skim cut passed OR that we
347  are skipping this selection. */
348  cutIndexPassed++;
349  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
350  B2DEBUG(22, "Cutflow: Trigger cut passed: index = " << cutIndexPassed);
351 
352 
353 
354  /* Use ECLChannelMapper to get other detector indices for the crystals
355  For conversion from CellID to crate, shaper, and channel ids.
356  The initialization function automatically checks to see if the
357  object has been initialized and ifthe payload has changed and
358  thus needs updating. */
359  bool ECLchannelMapHasChanged = m_channelMapDB.hasChanged();
360  if (ECLchannelMapHasChanged) {
361  B2INFO("ECLBhabhaTCollectorModule::collect() " << LogVar("ECLchannelMapHasChanged", ECLchannelMapHasChanged));
362  if (!m_crystalMapper->initFromDB()) {
363  B2FATAL("ECLBhabhaTCollectorModule::collect() : Can't initialize eclChannelMapper!");
364  }
365  }
366 
367 
368  //== Get expected energies and calibration constants from DB. Need to call
369  // hasChanged() for later comparison
370  if (m_ElectronicsDB.hasChanged()) {
371  m_Electronics = m_ElectronicsDB->getCalibVector();
372  }
373  if (m_ElectronicsTimeDB.hasChanged()) {
374  m_ElectronicsTime = m_ElectronicsTimeDB->getCalibVector();
375  }
376  if (m_FlightTimeDB.hasChanged()) {
377  m_FlightTime = m_FlightTimeDB->getCalibVector();
378  }
379 
380  // Get the previous crystal time offset (the same thing that this calibration is meant to calculate).
381  // This can be used for testing purposes, and for the crate time offset.
382  if (m_PreviousCrystalTimeDB.hasChanged()) {
383  m_PreviousCrystalTime = m_PreviousCrystalTimeDB->getCalibVector();
384  m_PreviousCrystalTimeUnc = m_PreviousCrystalTimeDB->getCalibUncVector();
385  }
386 
387  B2DEBUG(29, "Finished checking if previous crystal time payload has changed");
388  if (m_CrateTimeDB.hasChanged()) {
389  m_CrateTime = m_CrateTimeDB->getCalibVector();
390  m_CrateTimeUnc = m_CrateTimeDB->getCalibUncVector();
391  }
392  B2DEBUG(29, "Finished checking if previous crate time payload has changed");
393  B2DEBUG(29, "m_CrateTime size = " << m_CrateTime.size());
394  B2DEBUG(25, "Crate time +- uncertainty [0]= " << m_CrateTime[0] << " +- " << m_CrateTimeUnc[0]);
395  B2DEBUG(25, "Crate time +- uncertainty [8735]= " << m_CrateTime[8735] << " +- " << m_CrateTimeUnc[8735]);
396 
397  B2DEBUG(29, "Finished checking if previous crate time payload has changed");
398  if (m_RefCrystalsCalibDB.hasChanged()) {
399  m_RefCrystalsCalib = m_RefCrystalsCalibDB->getReferenceCrystals();
400  }
401  B2DEBUG(29, "Finished checking if reference crystal cell ids payload has changed");
402 
403 
404  B2DEBUG(25, "ECLBhabhaTCollector:: loaded ECLCrystalTimeOffset from the database"
405  << LogVar("IoV", m_PreviousCrystalTimeDB.getIoV())
406  << LogVar("Checksum", m_PreviousCrystalTimeDB.getChecksum()));
407  B2DEBUG(25, "ECLBhabhaTCollector:: loaded ECLCrateTimeOffset from the database"
408  << LogVar("IoV", m_CrateTimeDB.getIoV())
409  << LogVar("Checksum", m_CrateTimeDB.getChecksum()));
410  B2DEBUG(25, "ECLBhabhaTCollector:: loaded ECLCrystalElectronics from the database"
411  << LogVar("IoV", m_ElectronicsDB.getIoV())
412  << LogVar("Checksum", m_ElectronicsDB.getChecksum()));
413  B2DEBUG(25, "ECLBhabhaTCollector:: loaded ECLCrystalElectronicsTime from the database"
414  << LogVar("IoV", m_ElectronicsTimeDB.getIoV())
415  << LogVar("Checksum", m_ElectronicsTimeDB.getChecksum()));
416  B2DEBUG(25, "ECLBhabhaTCollector:: loaded ECLCrystalFlightTime from the database"
417  << LogVar("IoV", m_FlightTimeDB.getIoV())
418  << LogVar("Checksum", m_FlightTimeDB.getChecksum()));
419  B2DEBUG(25, "ECLBhabhaTCollector:: loaded ECLReferenceCrystalPerCrateCalib from the database"
420  << LogVar("IoV", m_RefCrystalsCalibDB.getIoV())
421  << LogVar("Checksum", m_RefCrystalsCalibDB.getChecksum()));
422 
423 
424 
425  // Conversion coefficient from ADC ticks to nanoseconds
426  // TICKS_TO_NS ~ 0.4913 ns/clock tick
427  // 1/(4fRF) = 0.4913 ns/clock tick, where fRF is the accelerator RF frequency
428  const double TICKS_TO_NS = 1.0 / (4.0 * EclConfiguration::m_rf) * 1e3;
429 
430 
431  vector<float> Crate_time_ns(52, 0.0);
433  // Make a crate time offset vector with an entry per crate (instead of per crystal) and convert from ADC counts to ns.
434  for (int crysID = 1; crysID <= 8736; crysID++) {
435  int crateID_temp = m_crystalMapper->getCrateID(crysID);
436  Crate_time_ns[crateID_temp - 1] = m_CrateTime[crysID] * TICKS_TO_NS;
437  }
438 
439 
440 
446  for (int crateID_temp = 1; crateID_temp <= 52; crateID_temp++) {
447  getObjectPtr<TH1F>("refCrysIDzeroingCrate")->Fill(m_RefCrystalsCalib[crateID_temp - 1] + 0.001);
448  }
449 
450 
452  for (int crysID = 1; crysID <= 8736; crysID++) {
453  getObjectPtr<TH1F>("TsDatabase")->SetBinContent(crysID + 0.001, m_PreviousCrystalTime[crysID - 1]);
454  getObjectPtr<TH1F>("TsDatabaseUnc")->SetBinContent(crysID + 0.001, m_PreviousCrystalTimeUnc[crysID - 1]);
455  getObjectPtr<TH1F>("TcrateDatabase")->SetBinContent(crysID + 0.001, m_CrateTime[crysID - 1]);
456  getObjectPtr<TH1F>("TcrateUncDatabase")->SetBinContent(crysID + 0.001, m_CrateTimeUnc[crysID - 1]);
457  }
458  if (m_storeCalib) {
459  B2INFO("ECLBhabhaTCollector:: ECLCrystalTimeOffset from the database information:"
460  << LogVar("IoV", m_PreviousCrystalTimeDB.getIoV())
461  << LogVar("Checksum", m_PreviousCrystalTimeDB.getChecksum()));
462  B2INFO("First event so print out previous ts values");
463  for (int crysID = 1; crysID <= 8736; crysID++) {
464  B2INFO("cid = " << crysID << ", Ts previous = " << m_PreviousCrystalTime[crysID - 1]);
465  }
466  m_storeCalib = false;
467  }
468 
469 
470 
471 
472  for (int crateID_temp = 1; crateID_temp <= 52; crateID_temp++) {
473  getObjectPtr<TH1F>("tcrateDatabase_ns")->SetBinContent(crateID_temp + 0.001, Crate_time_ns[crateID_temp - 1]);
474  }
475 
476  // Use a histogram with only one bin as a counter to know the number of times the database histograms were filled.
477  // This is mostly useful for the talg when running over multiple runs and trying to read ts values.
478  getObjectPtr<TH1I>("databaseCounter")->SetBinContent(1, 1);
479 
480 
481 
482  // Save what CDC event t0 correction was applied
483  getObjectPtr<TH1F>("CDCEventT0Correction")->SetBinContent(1, m_hadronEventT0_TO_bhabhaEventT0_correction);
484 
485 
486 
487 
488  /* Getting the event t0 using the full event t0 rather than from the CDC specifically */
489  double evt_t0 = -1;
490  double evt_t0_unc = -1;
491  double evt_t0_ECL_closestCDC = -1;
492  double evt_t0_ECL_minChi2 = -1;
493 
494  // Determine if there is an event t0 to use and then extract the information about it
495  if (!m_eventT0.isValid()) {
496  //cout << "event t0 not valid\n";
497  return;
498  } else if (!m_eventT0->hasTemporaryEventT0(Const::EDetector::CDC)) {
499  //cout << "no event t0\n";
500  return;
501  } else {
502  // Event has a t0 from CDC
503  cutIndexPassed++;
504  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
505  B2DEBUG(22, "Cutflow: Event t0 exists: index = " << cutIndexPassed);
506 
507 
508  // Get event t0 from CDC. We don't want event t0 from ECL as we are calibrating the ECL wrt the more accurately measured time measurements of the time. Start with the CDC since it has an event t0 but in the future we may switch to the TOP detector.
509  // Based on the information from Thomas Hauth <Thomas.Hauth@kit.edu> (leaving physics) we should take the last event t0 in the list of event t0's from the CDC as the later event t0 measurements are calculated in slower but more accurate ways.
510  vector<EventT0::EventT0Component> evt_t0_list = m_eventT0->getTemporaryEventT0s(Const::EDetector::CDC);
511  evt_t0 = evt_t0_list.back().eventT0; // time value
512  evt_t0_unc = evt_t0_list.back().eventT0Uncertainty; // uncertainty on event t0
513 
514 
515  // Correct the CDC event t0 value for the bhabha bias
516  evt_t0 = evt_t0 + m_hadronEventT0_TO_bhabhaEventT0_correction; // Bias not yet fixed in CDC t0 reco.
517 
518 
519  // Get the ECL event t0 for comparison - validations
520  if (m_eventT0->hasTemporaryEventT0(Const::EDetector::ECL)) {
521  vector<EventT0::EventT0Component> evt_t0_list_ECL = m_eventT0->getTemporaryEventT0s(Const::EDetector::ECL);
522 
523 
524  double smallest_CDC_ECL_t0_diff = fabs(evt_t0_list_ECL[0].eventT0 - evt_t0);
525  int smallest_CDC_ECL_t0_diff_idx = 0;
526  for (long unsigned int ECLi = 0; ECLi < evt_t0_list_ECL.size(); ECLi++) {
527  double tempt_ECL_t0 = evt_t0_list_ECL[ECLi].eventT0;
528  if (fabs(tempt_ECL_t0 - evt_t0) < smallest_CDC_ECL_t0_diff) {
529  smallest_CDC_ECL_t0_diff = fabs(tempt_ECL_t0 - evt_t0);
530  smallest_CDC_ECL_t0_diff_idx = ECLi;
531  }
532  }
533 
534  evt_t0_ECL_closestCDC = evt_t0_list_ECL[smallest_CDC_ECL_t0_diff_idx].eventT0; // time value
535  B2DEBUG(26, "evt_t0_ECL_closestCDC = " << evt_t0_ECL_closestCDC);
536 
537 
538 
539  double smallest_ECL_t0_minChi2 = evt_t0_list_ECL[0].quality;
540  int smallest_ECL_t0_minChi2_idx = 0;
541 
542  B2DEBUG(26, "evt_t0_list_ECL[0].quality = " << evt_t0_list_ECL[0].quality
543  << ", with ECL event t0 = " << evt_t0_list_ECL[0].eventT0);
544 
545  for (long unsigned int ECLi = 0; ECLi < evt_t0_list_ECL.size(); ECLi++) {
546  B2DEBUG(26, "evt_t0_list_ECL[" << ECLi << "].quality = " << evt_t0_list_ECL[ECLi].quality
547  << ", with ECL event t0 = " <<
548  evt_t0_list_ECL[ECLi].eventT0);
549  if (evt_t0_list_ECL[ECLi].quality < smallest_ECL_t0_minChi2) {
550  smallest_ECL_t0_minChi2 = evt_t0_list_ECL[ECLi].quality;
551  smallest_ECL_t0_minChi2_idx = ECLi;
552  }
553  }
554 
555  evt_t0_ECL_minChi2 = evt_t0_list_ECL[smallest_ECL_t0_minChi2_idx].eventT0; // time value
556 
557  B2DEBUG(26, "evt_t0_ECL_minChi2 = " << evt_t0_ECL_minChi2);
558  B2DEBUG(26, "smallest_ECL_t0_minChi2_idx = " << smallest_ECL_t0_minChi2_idx);
559  }
560  }
561 
562 
563 
564  /* Determine the energies for each of the crystals since this isn't naturally connected to the cluster.
565  Also determine the indexing of the ecl cal digits and the ecl digits
566  Taken from Chris's ec/modules/eclGammaGammaECollector */
567 
568  // Resize vectors
569  m_EperCrys.resize(8736);
570  m_eclCalDigitID.resize(8736);
571  m_eclDigitID.resize(8736);
572 
573 
574  int idx = 0;
575  for (auto& eclCalDigit : m_eclCalDigitArray) {
576  int tempCrysID = eclCalDigit.getCellId() - 1;
577  m_EperCrys[tempCrysID] = eclCalDigit.getEnergy();
578  m_eclCalDigitID[tempCrysID] = idx;
579  idx++;
580  }
581 
582  idx = 0;
583  for (auto& eclDigit : m_eclDigitArray) {
584  int tempCrysID = eclDigit.getCellId() - 1;
585  m_eclDigitID[tempCrysID] = idx;
586  idx++;
587  }
588 
589 
590 
591 
592  //---------------------------------------------------------------------
593  //..Some utilities
594  ClusterUtils cUtil;
595  const TVector3 clustervertex = cUtil.GetIPPosition();
596  PCmsLabTransform boostrotate;
597 
598  //---------------------------------------------------------------------
599  //..Track properties, including 2 maxp tracks. Use pion (211) mass hypothesis,
600  // which is the only particle hypothesis currently available???
601  double maxp[2] = {0., 0.};
602  int maxiTrk[2] = { -1, -1};
603  int nTrkAll = tracks.getEntries();
604 
605  int nTrkLoose = 0;
606  int nTrkTight = 0;
608  /* Loop over all the tracks to define the tight and loose selection tracks.
609  We will select events with only 2 tight tracks and no additional loose tracks.
610  Tight tracks are a subset of looses tracks. */
611  for (int iTrk = 0; iTrk < nTrkAll; iTrk++) {
612  // Get track biasing towards the particle being a pion based on what particle types
613  // are used for reconstruction at this stage.
614  const TrackFitResult* tempTrackFit = tracks[iTrk]->getTrackFitResultWithClosestMass(Const::pion);
615  if (not tempTrackFit) {continue;}
616 
617  // Collect track info to be used for categorizing
618  short charge = tempTrackFit->getChargeSign();
619  double z0 = tempTrackFit->getZ0();
620  double d0 = tempTrackFit->getD0();
621  int nCDChits = tempTrackFit->getHitPatternCDC().getNHits();
622  double p = tempTrackFit->getMomentum().Mag();
623 
624  // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
625  //== Save debug TTree with detailed information if necessary.
626  m_tree_d0 = d0;
627  m_tree_z0 = z0;
628  m_tree_p = p;
629  m_charge = charge;
630  m_tree_nCDChits = nCDChits;
631 
632  if (m_saveTree) {
633  m_dbgTree_tracks->Fill();
634  }
635  //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
636 
637 
638  /* Test if loose track */
639 
640  // d0 and z0 cuts
641  if (fabs(d0) > m_looseTrkD0) {
642  continue;
643  }
644  if (fabs(z0) > m_looseTrkZ0) {
645  continue;
646  }
647  // Number of hits in the CDC
648  if (nCDChits < 1) {
649  continue;
650  }
651  nTrkLoose++;
652 
653 
654 
655  /* Test if the loose track is also a tight track */
656 
657  // Number of hits in the CDC
658  if (nCDChits < 20) {
659  continue;
660  }
661 
662 
663  // d0 and z0 cuts
664  if (fabs(d0) > m_tightTrkD0) {
665  continue;
666  }
667  if (fabs(z0) > m_tightTrkZ0) {
668  continue;
669  }
670  nTrkTight++;
671 
672  // Sorting of tight tracks. Not really required as we only want two tight tracks (at the moment) but okay.
673  //..Find the maximum p negative [0] and positive [1] tracks
674  int icharge = 0;
675  if (charge > 0) {icharge = 1;}
676  if (p > maxp[icharge]) {
677  maxp[icharge] = p;
678  maxiTrk[icharge] = iTrk;
679  }
680 
681  }
682  /* After that last section the numbers of loose and tight tracks are known as well as the
683  index of the loose tracks that have the highest p negatively charged and highest p positively
684  charged tracks as measured in the centre of mass frame */
685 
686 
687  if (nTrkTight != 2) {
688  return;
689  }
690  // There are exactly two tight tracks
691  cutIndexPassed++;
692  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
693  B2DEBUG(22, "Cutflow: Two tight tracks: index = " << cutIndexPassed);
694 
695 
696  if (nTrkLoose != 2) {
697  return;
698  }
699  // There are exactly two loose tracks as well, i.e. no additional loose tracks
700  cutIndexPassed++;
701  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
702  B2DEBUG(22, "Cutflow: No additional loose tracks: index = " << cutIndexPassed);
703 
704  /* Determine if the two tracks have the opposite electric charge.
705  We know this because the track indices stores the max pt track in [0] for negatively charged track
706  and [1] fo the positively charged track. If both are filled then both a negatively charged
707  and positively charged track were found. */
708  bool oppositelyChargedTracksPassed = maxiTrk[0] != -1 && maxiTrk[1] != -1;
709  if (!oppositelyChargedTracksPassed) {
710  return;
711  }
712  // The two tracks have the opposite electric charges.
713  cutIndexPassed++;
714  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
715  B2DEBUG(22, "Cutflow: Oppositely charged tracks: index = " << cutIndexPassed);
716 
717 
718 
719 
720  //---------------------------------------------------------------------
721  /* Determine associated energy clusters to each of the two tracks. Sum the energies of the
722  multiple clusters to each track and find the crystal with the maximum energy within all
723  the sets of clusters associated to the tracks*/
724  double trkEClustLab[2] = {0., 0.};
725  double trkEClustCOM[2] = {0., 0.};
726  double trkpLab[2];
727  double trkpCOM[2];
728  TLorentzVector trkp4Lab[2];
729  TLorentzVector trkp4COM[2];
730 
731  // Index of the cluster and the crystal that has the highest energy crystal for the two tracks
732  int crysIDMax[2] = { -1, -1 };
733  double crysEMax[2] = { -1, -1 };
734  double crysE2Max[2] = { -1, -1 };
735  int numClustersPerTrack[2] = { 0, 0 };
736 
737  double clusterTime[2] = {0, 0};
738 
739  double E_DIV_p[2];
740 
741  vector<double> time_ECLCaldigits_bothClusters;
742  vector<int> cid_ECLCaldigits_bothClusters;
743  vector<double> E_ECLCaldigits_bothClusters;
744  vector<double> amp_ECLDigits_bothClusters;
745  vector<int> chargeID_ECLCaldigits_bothClusters;
746 
747  for (int icharge = 0; icharge < 2; icharge++) {
748  if (maxiTrk[icharge] > -1) {
749  B2DEBUG(22, "looping over the 2 max pt tracks");
750 
751  const TrackFitResult* tempTrackFit = tracks[maxiTrk[icharge]]->getTrackFitResultWithClosestMass(Const::pion);
752  if (not tempTrackFit) {continue;}
753  trkp4Lab[icharge] = tempTrackFit->get4Momentum();
754  trkp4COM[icharge] = boostrotate.rotateLabToCms() * trkp4Lab[icharge];
755  trkpLab[icharge] = trkp4Lab[icharge].Rho();
756  trkpCOM[icharge] = trkp4COM[icharge].Rho();
757 
758 
759  /* For each cluster associated to the current track, sum up the energies to get the total
760  energy of all clusters associated to the track and find which crystal has the highest
761  energy from all those clusters*/
762  auto eclClusterRelationsFromTracks = tracks[maxiTrk[icharge]]->getRelationsTo<ECLCluster>();
763  for (unsigned int clusterIdx = 0; clusterIdx < eclClusterRelationsFromTracks.size(); clusterIdx++) {
764 
765  B2DEBUG(22, "Looking at clusters. index = " << clusterIdx);
766  auto cluster = eclClusterRelationsFromTracks[clusterIdx];
767  bool goodClusterType = false;
768 
769  if (cluster->hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons)) {
770  trkEClustLab[icharge] += cluster->getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons);
771  goodClusterType = true;
772  numClustersPerTrack[icharge]++;
773  }
774 
775  if (goodClusterType) {
776 
777  clusterTime[icharge] = cluster->getTime();
778 
779  auto eclClusterRelations = cluster->getRelationsTo<ECLCalDigit>("ECLCalDigits");
780 
781  // Find the crystal that has the largest energy
782  for (unsigned int ir = 0; ir < eclClusterRelations.size(); ir++) {
783  const auto calDigit = eclClusterRelations.object(ir);
784  int tempCrysID = calDigit->getCellId() - 1;
785  double tempE = m_EperCrys[tempCrysID];
786 
787  int eclDigitIndex = m_eclDigitID[tempCrysID];
788  ECLDigit* ecl_dig = m_eclDigitArray[eclDigitIndex];
789 
790  // for the max E crystal
791  if (tempE > crysEMax[icharge]) {
792  // Set 2nd highest E crystal to the info from the highest E crystal
793  crysE2Max[icharge] = crysEMax[icharge];
794  // Set the highest E crystal to the current crystal
795  crysEMax[icharge] = tempE;
796  crysIDMax[icharge] = tempCrysID;
797  }
798  // for the 2nd highest E crystal
799  if (tempE > crysE2Max[icharge] && tempCrysID != crysIDMax[icharge]) {
800  crysE2Max[icharge] = tempE;
801  }
802 
803  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
804  // If we drop the information about the second highest energy crystal we could use
805  // m_eclClusterArray[ic]->getMaxECellId()
806 
807  B2DEBUG(26, "calDigit(ir" << ir << ") time = " << calDigit->getTime() << "ns , with E = " << tempE << " GeV");
808  time_ECLCaldigits_bothClusters.push_back(calDigit->getTime());
809  cid_ECLCaldigits_bothClusters.push_back(tempCrysID);
810  E_ECLCaldigits_bothClusters.push_back(tempE);
811  amp_ECLDigits_bothClusters.push_back(ecl_dig->getAmp());
812  chargeID_ECLCaldigits_bothClusters.push_back(icharge);
813 
814  }
815  }
816  }
817  trkEClustCOM[icharge] = trkEClustLab[icharge] * trkpCOM[icharge] / trkpLab[icharge];
818 
819  // Check both electrons to see if their cluster energy / track momentum is good.
820  // The Belle II physics book shows that this is the main way of separating electrons from other particles
821  // Done in the centre of mass reference frame although I believe E/p is invariant under a boost.
822  E_DIV_p[icharge] = trkEClustCOM[icharge] / trkpCOM[icharge];
823 
824  }
825  }
826  /* At the end of this section the 3-momenta magnitudes and the cluster energies are known
827  for the two saved track indices for both the lab and COM frames.
828  The crystal with the maximum energy, one associated to each track, is recorded*/
829 
830 
831 
832  //=== Check each crystal in the processed event and fill histogram.
833 
834  int numCrystalsPassingCuts = 0;
835 
836  int crystalIDs[2] = { -1, -1};
837  int crateIDs[2] = { -1, -1};
838  double ts_prevCalib[2] = { -1, -1};
839  double tcrate_prevCalib[2] = { -1, -1};
840  double times_noPreviousCalibrations[2] = { -1, -1};
841  bool crystalCutsPassed[2] = {false, false};
842  double crystalEnergies[2] = { -1, -1};
843  double crystalEnergies2[2] = { -1, -1};
844 
845  for (int iCharge = 0; iCharge < 2; iCharge++) {
846  int crystal_idx = crysIDMax[iCharge];
847  int eclCalDigitIndex = m_eclCalDigitID[crystal_idx];
848  int eclDigitIndex = m_eclDigitID[crystal_idx];
849 
850  ECLDigit* ecl_dig = m_eclDigitArray[eclDigitIndex];
851  ECLCalDigit* ecl_cal = m_eclCalDigitArray[eclCalDigitIndex];
852 
853  //== Check whether specific ECLDigits should be excluded.
854 
855  auto en = ecl_cal->getEnergy();
856  auto amplitude = ecl_dig->getAmp();
857  crystalEnergies[iCharge] = en;
858 
859  int cid = ecl_dig->getCellId();
860  double time = ecl_dig->getTimeFit() * TICKS_TO_NS - evt_t0;
861 
862  // Offset time by electronics calibration and flight time calibration.
863  time -= m_ElectronicsTime[cid - 1] * TICKS_TO_NS;
864  time -= m_FlightTime[cid - 1];
865 
866 
867  // Apply the time walk correction: time shift as a function of the amplitude corrected by the electronics calibration.
868  // The electronics calibration also accounts for crystals that have a dead pre-amp and thus half the normal amplitude.
869  double energyTimeShift = m_ECLTimeUtil->energyDependentTimeOffsetElectronic(amplitude * m_Electronics[cid - 1]) * TICKS_TO_NS;
870 
871  B2DEBUG(29, "cellid = " << cid << ", amplitude = " << amplitude << ", time before t(E) shift = " << time <<
872  ", t(E) shift = " << energyTimeShift << " ns");
873  time -= energyTimeShift;
874 
875 
876  // Cell ID should be within specified range.
877  if (cid < m_minCrystal || cid > m_maxCrystal) continue;
878 
879  // Absolute time should be in specified range condition.
880  if (fabs(time) > m_timeAbsMax) continue;
881 
882  // Fit quality flag -- choose only events with best fit quality
883  if (ecl_dig->getQuality() != 0) continue;
884 
885  //== Save time and crystal information. Fill plot after both electrons are tested
886  crystalIDs[iCharge] = cid;
887  crateIDs[iCharge] = m_crystalMapper->getCrateID(ecl_cal->getCellId());
888 
889 
890  ts_prevCalib[iCharge] = m_PreviousCrystalTime[cid - 1] * TICKS_TO_NS;
891  tcrate_prevCalib[iCharge] = m_CrateTime[cid - 1] * TICKS_TO_NS;
892  times_noPreviousCalibrations[iCharge] = time;
893 
894 
895  B2DEBUG(26, "iCharge = " << iCharge);
896  B2DEBUG(26, "crateIDs[iCharge] = " << crateIDs[iCharge]);
897  B2DEBUG(26, "times_noPreviousCalibrations[iCharge] = " << times_noPreviousCalibrations[iCharge]);
898  B2DEBUG(26, "tcrate_prevCalib[iCharge] = " << tcrate_prevCalib[iCharge]);
899  B2DEBUG(26, "ts_prevCalib[iCharge] = " << ts_prevCalib[iCharge]);
900 
901 
902  crystalCutsPassed[iCharge] = true;
903 
904 
905  // For second most energetic energy crystal
906  crystalEnergies2[iCharge] = crysE2Max[iCharge];
907 
908 
909 // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Tree saving
910  //== Save debug TTree with detailed information if necessary.
911  m_tree_cid = ecl_dig->getCellId();
912  m_tree_amp = ecl_dig->getAmp();
913  m_tree_en = en;
914  m_tree_E1Etot = en / trkEClustLab[iCharge];
915  m_tree_E1E2 = en / crystalEnergies2[iCharge];
916  m_tree_E1p = en / trkpLab[iCharge];
917  m_tree_timetsPreviousTimeCalibs = time - ts_prevCalib[iCharge] - tcrate_prevCalib[iCharge];
918  m_tree_timeF = ecl_dig->getTimeFit() * TICKS_TO_NS;
919  m_tree_time = time;
920  m_tree_quality = ecl_dig->getQuality();
921  m_tree_t0 = evt_t0;
922  m_tree_t0_unc = evt_t0_unc;
923  m_E_DIV_p = E_DIV_p[iCharge];
924  m_tree_evtNum = m_EventMetaData->getEvent();
925  m_crystalCrate = m_crystalMapper->getCrateID(ecl_cal->getCellId());
926  m_runNum = m_EventMetaData->getRun();
927 
928  if (m_saveTree) {
929  m_dbgTree_electrons->Fill();
930  }
931 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Tree saving
932 
933  // Fill histogram with information about maximum energy crystal energy fraction
934  getObjectPtr<TH1F>("maxEcrsytalEnergyFraction")->Fill(en / trkEClustLab[iCharge]);
935 
936 
937  }
938 
939 
940 
941  // Check both electrons to see if their cluster energy / track momentum is good.
942  // The Belle II physics book shows that this is the main way of separating electrons from other particles
943  // Done in the centre of mass reference frame although I believe E/p is invariant under a boost.
944  bool E_DIV_p_instance_passed[2] = {false, false};
945  double E_DIV_p_CUT = 0.7;
946  for (int icharge = 0; icharge < 2; icharge++) {
947  E_DIV_p_instance_passed[icharge] = E_DIV_p[icharge] > E_DIV_p_CUT;
948  }
949  if (!E_DIV_p_instance_passed[0] || !E_DIV_p_instance_passed[1]) {
950  return;
951  }
952  // E/p sufficiently large
953  cutIndexPassed++;
954  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
955  B2DEBUG(22, "Cutflow: E_i/p_i > " << E_DIV_p_CUT << ": index = " << cutIndexPassed);
956 
957 
958 
959  // Start of cuts on both the combined system of tracks and energy clusters
960 
961  double invMassTrk = (trkp4Lab[0] + trkp4Lab[1]).M();
962  double invMass_CUT = 0.9;
963  m_massInvTracks = invMassTrk; // invariant mass of the two tracks
964 
965 // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Tree saving
966  if (m_saveTree) {
967  m_dbgTree_event->Fill();
968  }
969 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Tree saving
970 
971  bool invMassCutsPassed = invMassTrk > (invMass_CUT * boostrotate.getCMSEnergy());
972  if (!invMassCutsPassed) {
973  return;
974  }
975  // Invariable mass of the two tracks are above the minimum
976  cutIndexPassed++;
977  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
978  B2DEBUG(22, "Cutflow: m(track 1+2) > " << invMass_CUT << "*E_COM = " << invMass_CUT << " * " << boostrotate.getCMSEnergy() <<
979  " : index = " << cutIndexPassed);
980 
981 
982 
983  //== Fill output histogram.
984  for (int iCharge = 0; iCharge < 2; iCharge++) {
985  if (crystalCutsPassed[iCharge]) {
986  getObjectPtr<TH2F>("TimevsCrysPrevCrateCalibPrevCrystCalib")->Fill((crystalIDs[iCharge]) + 0.001,
987  times_noPreviousCalibrations[iCharge] - ts_prevCalib[iCharge] - tcrate_prevCalib[iCharge] , 1);
988  getObjectPtr<TH2F>("TimevsCratePrevCrateCalibPrevCrystCalib")->Fill((crateIDs[iCharge]) + 0.001,
989  times_noPreviousCalibrations[iCharge] - ts_prevCalib[iCharge] - tcrate_prevCalib[iCharge], 1);
990  getObjectPtr<TH2F>("TimevsCrysNoCalibrations")->Fill((crystalIDs[iCharge]) + 0.001, times_noPreviousCalibrations[iCharge], 1);
991  getObjectPtr<TH2F>("TimevsCrateNoCalibrations")->Fill((crateIDs[iCharge]) + 0.001, times_noPreviousCalibrations[iCharge], 1);
992  getObjectPtr<TH2F>("TimevsCrysPrevCrateCalibNoCrystCalib")->Fill((crystalIDs[iCharge]) + 0.001,
993  times_noPreviousCalibrations[iCharge] - tcrate_prevCalib[iCharge], 1);
994  getObjectPtr<TH2F>("TimevsCrateNoCrateCalibPrevCrystCalib")->Fill((crateIDs[iCharge]) + 0.001,
995  times_noPreviousCalibrations[iCharge] - ts_prevCalib[iCharge] , 1);
996 
997  // Record number of crystals used from the event. Should be exactly two.
998  numCrystalsPassingCuts++;
999 
1000  }
1001  }
1002 
1003 
1004  // Change cutflow method for this bit ... don't call return because we used to call the hadron cluster stuff afterwards
1005  //
1006  if (crystalCutsPassed[0] || crystalCutsPassed[1]) {
1007  // At least one ECL crystal time and quality cuts passed
1008  cutIndexPassed++;
1009  getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
1010  B2DEBUG(22, "Cutflow: At least one crystal time and quality cuts passed: index = " << cutIndexPassed);
1011 
1012  getObjectPtr<TH1F>("numCrystalEntriesPerEvent")->Fill(numCrystalsPassingCuts);
1013  }
1014 
1015 
1016  // Save final information to the tree after all cuts are applied
1017  for (int iCharge = 0; iCharge < 2; iCharge++) {
1018  if (crystalCutsPassed[iCharge]) {
1019  // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Tree saving
1020  m_tree_evtNum = m_EventMetaData->getEvent();
1021  m_tree_cid = crystalIDs[iCharge];
1022  //m_tree_time = times[iCharge];
1023  m_tree_time = times_noPreviousCalibrations[iCharge];
1024  m_crystalCrate = crateIDs[iCharge];
1025  m_runNum = m_EventMetaData->getRun();
1026  m_tree_en = crystalEnergies[iCharge]; // for studies of ts as a function of energy
1027  m_tree_E1Etot = crystalEnergies[iCharge] / trkEClustLab[iCharge];
1028  m_tree_E1E2 = crystalEnergies[iCharge] / crystalEnergies2[iCharge];
1029  m_tree_E1p = crystalEnergies[iCharge] / trkpLab[iCharge];
1030  m_tree_timetsPreviousTimeCalibs = times_noPreviousCalibrations[iCharge] - ts_prevCalib[iCharge] - tcrate_prevCalib[iCharge];
1031  m_tree_t0 = evt_t0;
1032  m_tree_t0_ECLclosestCDC = evt_t0_ECL_closestCDC;
1033  m_tree_t0_ECL_minChi2 = evt_t0_ECL_minChi2;
1034  m_tree_tClust = clusterTime[iCharge];
1035 
1036  m_massInvTracks = invMassTrk; // This is probably already set but I'll set it again anyways just so that it is clear
1037 
1038  if (m_saveTree) {
1039  m_dbgTree_allCuts->Fill();
1040  }
1041  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Tree saving
1042  }
1043  }
1044 
1045 
1046 
1047 
1048  if (crystalCutsPassed[0] && crystalCutsPassed[1] &&
1049  numClustersPerTrack[0] == 1 && numClustersPerTrack[1] == 1) {
1050  m_tree_enNeg = trkEClustLab[0];
1051  m_tree_enPlus = trkEClustLab[1];
1052  m_tree_tClustNeg = clusterTime[0];
1053  m_tree_tClustPos = clusterTime[1];
1054  m_tree_maxEcrystPosClust = times_noPreviousCalibrations[0] - ts_prevCalib[0] - tcrate_prevCalib[0];
1055  m_tree_maxEcrystNegClust = times_noPreviousCalibrations[1] - ts_prevCalib[1] - tcrate_prevCalib[1];
1056  m_tree_t0 = evt_t0;
1057  m_tree_t0_ECLclosestCDC = evt_t0_ECL_closestCDC;
1058  m_tree_t0_ECL_minChi2 = evt_t0_ECL_minChi2;
1059 
1060  // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Tree saving
1061  if (m_saveTree) {
1062  m_dbgTree_evt_allCuts->Fill();
1063  }
1064  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Tree saving
1065  }
1066 
1067 
1068  B2DEBUG(26, "m_tree_maxEcrystPosClust + evt_t0 = " << m_tree_maxEcrystPosClust + evt_t0);
1069  B2DEBUG(26, "m_tree_maxEcrystNegClust + evt_t0 = " << m_tree_maxEcrystNegClust + evt_t0);
1070  B2DEBUG(26, "CDC evt_t0 = " << evt_t0);
1071  B2DEBUG(26, "ECL min chi2 even t0, m_tree_t0_ECL_minChi2 = " << m_tree_t0_ECL_minChi2);
1072 
1073 
1074 
1075  for (long unsigned int digit_i = 0; digit_i < time_ECLCaldigits_bothClusters.size(); digit_i++) {
1076  m_runNum = m_EventMetaData->getRun();
1077  m_tree_evtNum = m_EventMetaData->getEvent();
1078  m_tree_ECLCalDigitTime = time_ECLCaldigits_bothClusters[digit_i];
1079  m_tree_ECLCalDigitE = E_ECLCaldigits_bothClusters[digit_i];
1080  m_tree_ECLDigitAmplitude = amp_ECLDigits_bothClusters[digit_i];
1081  m_tree_t0 = evt_t0;
1082  m_tree_t0_ECLclosestCDC = evt_t0_ECL_closestCDC;
1083  m_tree_t0_ECL_minChi2 = evt_t0_ECL_minChi2;
1084  m_tree_timetsPreviousTimeCalibs = times_noPreviousCalibrations[chargeID_ECLCaldigits_bothClusters[digit_i]] -
1085  ts_prevCalib[chargeID_ECLCaldigits_bothClusters[digit_i]] -
1086  tcrate_prevCalib[chargeID_ECLCaldigits_bothClusters[digit_i]];
1087  m_tree_cid = cid_ECLCaldigits_bothClusters[digit_i];
1088 
1089  // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Tree saving
1090  if (m_saveTree) {
1091  m_dbgTree_crys_allCuts->Fill();
1092  }
1093  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Tree saving
1094 
1095  }
1096 
1097 
1098  B2DEBUG(26, "This was for event number = " << m_tree_evtNum);
1099 
1100 }
1101 
1102 
Calibration collector module base class.
Class to provide momentum-related information from ECLClusters.
Definition: ClusterUtils.h:34
const TVector3 GetIPPosition()
Returns default IP position from beam parameters.
static const ChargedStable pion
charged pion particle
Definition: Const.h:542
This module generates time vs crystal 2D histograms to later (in eclBhabhaTAlgorithm) find time cryst...
void collect() override
Select events and crystals and accumulate histograms.
void prepare() override
Define histograms and read payloads from DB.
void inDefineHisto() override
Replacement for defineHisto() in CalibrationCollector modules.
virtual ~ECLBhabhaTCollectorModule()
Module destructor.
Class to store calibrated ECLDigits: ECLCalDigits.
Definition: ECLCalDigit.h:23
int getCellId() const
Get Cell ID.
Definition: ECLCalDigit.h:114
double getEnergy() const
Get Calibrated Energy.
Definition: ECLCalDigit.h:119
DB object to store correspondence table of type (Crate id, ShaperDSP id, Channel id) <-> (ECL CellID)
Definition: ECLChannelMap.h:44
ECL cluster data.
Definition: ECLCluster.h:27
@ c_nPhotons
CR is split into n photons (N1)
Class to store ECL digitized hits (output of ECLDigi) relation to ECLHit filled in ecl/modules/eclDig...
Definition: ECLDigit.h:24
int getAmp() const
Get Fitting Amplitude.
Definition: ECLDigit.h:70
int getQuality() const
Get Fitting Quality.
Definition: ECLDigit.h:80
int getCellId() const
Get Cell ID.
Definition: ECLDigit.h:64
int getTimeFit() const
Get Fitting Time.
Definition: ECLDigit.h:75
General DB object to store one reference crystal per per ECL crate for calibration purposes.
static constexpr double m_rf
accelerating RF, http://ptep.oxfordjournals.org/content/2013/3/03A006.full.pdf
unsigned short getNHits() const
Get the total Number of CDC hits in the fit.
Class to hold Lorentz transformations from/to CMS and boost vector.
double getCMSEnergy() const
Returns CMS energy of e+e- (aka.
const TLorentzRotation rotateLabToCms() const
Returns Lorentz transformation from Lab to CMS.
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
TLorentzVector get4Momentum() const
Getter for the 4Momentum at the closest approach of the track in the r/phi projection.
TVector3 getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
double getD0() const
Getter for d0.
double getZ0() const
Getter for z0.
HitPatternCDC getHitPatternCDC() const
Getter for the hit pattern in the CDC;.
Class to store variables with their name which were sent to the logging service.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
@ c_accept
Accept this event.
Abstract base class for different kinds of events.