Belle II Software development
eclBhabhaTimeCalibrationValidationCollectorModule.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 * Description: *
11 * Tool to perform validations using bhabha events. *
12 * The selections here are very similar to the selections used to *
13 * perform the bhabha based timing calibrations; however, *
14 * there are some small differences so that the cuts are slightly *
15 * different. Further differences could appear if the two codes *
16 * are not updated simultaneously if/when there are changes. *
17 * The intention of this code is just to make sure the calibrations *
18 * results are self consistent and to validate the calibrations *
19 * as a whole for a collection of bhabha events rather than to *
20 * validate the cluster times of each individual cluster from the *
21 * original calibration code. Hopefully the selection is looser *
22 * so that fewer events can be used to validate than are required *
23 * to perform the calibration itself. *
24 **************************************************************************/
25
26/* Own header. */
27#include <ecl/modules/eclBhabhaTimeCalibrationValidationCollector/eclBhabhaTimeCalibrationValidationCollectorModule.h>
28
29/* ECL headers. */
30#include <ecl/dataobjects/ECLCalDigit.h>
31#include <ecl/dataobjects/ECLElementNumbers.h>
32#include <ecl/dbobjects/ECLCrystalCalib.h>
33#include <ecl/digitization/EclConfiguration.h>
34
35/* Basf2 headers. */
36#include <analysis/utility/PCmsLabTransform.h>
37#include <framework/gearbox/Const.h>
38#include <mdst/dataobjects/ECLCluster.h>
39#include <mdst/dataobjects/HitPatternCDC.h>
40#include <mdst/dataobjects/Track.h>
41
42/* ROOT headers. */
43#include <TH2F.h>
44#include <TTree.h>
45
46using namespace Belle2;
47using namespace ECL;
48using namespace std;
49
50//-----------------------------------------------------------------
51// Register the Module
52//-----------------------------------------------------------------
53REG_MODULE(eclBhabhaTimeCalibrationValidationCollector);
54
55//-----------------------------------------------------------------
56// Implementation
57//-----------------------------------------------------------------
58
61 m_dbg_tree_electronClusters(0),
62 m_dbg_tree_event(0),
63 m_dbg_tree_run(0),
64 m_CrateTimeDB("ECLCrateTimeOffset"),
65 m_channelMapDB("ECLChannelMap")//,
66{
67 setDescription("This module validates the ECL cluster times");
68
69 addParam("timeAbsMax", m_timeAbsMax, // (Time in ns)
70 "Events with fabs(getTimeFit) > m_timeAbsMax "
71 "are excluded", (short)80);
72
73 addParam("saveTree", m_saveTree,
74 "If true, TTree 'tree' with more detailed event info is saved in "
75 "the output file specified by HistoManager",
76 false);
77
78 addParam("looseTrkZ0", m_looseTrkZ0, "max Z0 for loose tracks (cm)", 10.);
79 addParam("tightTrkZ0", m_tightTrkZ0, "max Z0 for tight tracks (cm)", 2.);
80 addParam("looseTrkD0", m_looseTrkD0, "max D0 for loose tracks (cm)", 2.);
81 addParam("tightTrkD0", m_tightTrkD0, "max D0 for tight tracks (cm)", 0.5); // beam pipe radius = 1cm in 2019
82 addParam("skipTrgSel", skipTrgSel, "boolean to skip the trigger skim selection", false);
83
84
85 // specify this flag if you need parallel processing
87}
88
90{
91}
92
94{
95
96}
97
99{
100 //=== Prepare TTree for debug output
101 if (m_saveTree) {
102 // Per electron cluster
103 m_dbg_tree_electronClusters = new TTree("tree_electronClusters",
104 "Validating crystal and crate time calibrations using electron clusters in events with lots of tracks and clusters") ;
105 m_dbg_tree_electronClusters->Branch("EventNum", &m_tree_evt_num) ->SetTitle("Event number") ;
106 m_dbg_tree_electronClusters->Branch("cluster_time", &m_tree_time) ->SetTitle("Cluster time t (calibrated), ns") ;
107 m_dbg_tree_electronClusters->Branch("clust_E", &m_E_electron_clust) ->SetTitle("Electron type cluster energy, GeV") ;
108 m_dbg_tree_electronClusters->Branch("t0", &m_tree_t0) ->SetTitle("T0, ns") ;
109 m_dbg_tree_electronClusters->Branch("t0_unc", &m_tree_t0_unc) ->SetTitle("T0 uncertainty, ns") ;
110 m_dbg_tree_electronClusters->Branch("runNum", &m_tree_run) ->SetTitle("Run number") ;
111 m_dbg_tree_electronClusters->Branch("CrystalCellID", &m_tree_cid) ->SetTitle("Cell ID, 1..8736") ;
112 m_dbg_tree_electronClusters->Branch("dt99", &m_tree_dt99) ->SetTitle("Cluster dt99, ns") ;
113 m_dbg_tree_electronClusters->SetAutoSave(10) ;
114
115 // Per event
116 m_dbg_tree_event = new TTree("tree_event",
117 "Validating crystal and crate time calibrations using electron clusters in events with lots of tracks and clusters") ;
118 m_dbg_tree_event->Branch("EventNum", &m_tree_evt_num) ->SetTitle("Event number") ;
119 m_dbg_tree_event->Branch("t0", &m_tree_t0) ->SetTitle("T0, ns") ;
120 m_dbg_tree_event->Branch("t0_unc", &m_tree_t0_unc) ->SetTitle("T0 uncertainty, ns") ;
121 m_dbg_tree_event->Branch("runNum", &m_tree_run) ->SetTitle("Run number") ;
122 m_dbg_tree_event->Branch("E0", &m_tree_E0) ->SetTitle("Highest E cluster E") ;
123 m_dbg_tree_event->Branch("E1", &m_tree_E1) ->SetTitle("2nd highest E cluster E") ;
124 m_dbg_tree_event->Branch("time_E0", &m_tree_time_fromE0) ->SetTitle("Cluster time of highest E cluster") ;
125 m_dbg_tree_event->Branch("time_E1", &m_tree_time_fromE1) ->SetTitle("Cluster time of 2nd highest E cluster") ;
126 m_dbg_tree_event->SetAutoSave(10) ;
127
128
129 // Per run
130 m_dbg_tree_run = new TTree("tree_run", "Storing crate time constants") ;
131 m_dbg_tree_run->Branch("runNum", &m_tree_run) ->SetTitle("Run number") ;
132 m_dbg_tree_run->Branch("crateid", &m_tree_crateid) ->SetTitle("Crate ID") ;
133 m_dbg_tree_run->Branch("tcrate", &m_tree_tcrate) ->SetTitle("Crate time") ;
134 m_dbg_tree_run->Branch("tcrate_unc", &m_tree_tcrate_unc) ->SetTitle("Crate time uncertainty") ;
135 m_dbg_tree_run->SetAutoSave(10) ;
136
137 }
138
139
140 //=== MetaData
141 B2INFO("eclBhabhaTimeCalibrationValidationCollector: Experiment = " << m_EventMetaData->getExperiment() <<
142 " run = " << m_EventMetaData->getRun()) ;
143
144 //=== Create histograms and register them in the data store
145
146 // Define the bin size, which is equivalent to the
147 double binSize = 2000.0 / pow(2, 12);
148 double halfBinSize = binSize / 2.0;
149
150 /* Determine the number of bins required to go from the edge of the bin centred
151 on zero to a value just larger than the negative cut off */
152 double nBinsNeg = floor((m_timeAbsMax - halfBinSize) / binSize);
153 double min_t = -nBinsNeg * binSize - halfBinSize; // lower edge value of left most bin
154 int nbins = nBinsNeg * 2 + 1; // number of negative time bins + t=0 bin + number of positive time bins
155 double max_t = min_t + nbins * binSize; // upper edge value of right most bin
156
157 /* Variable bin width information for the time information vs energy since
158 the time width should vary as a function of 1/E */
159 const Int_t N_E_BIN_EDGES = 64;
160 const Int_t N_E_BINS = N_E_BIN_EDGES - 1;
161 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};
162
163
164 auto cutflow = new TH1F("cutflow", " ;Cut label number ;Number of events passing cut", 10, 0, 10) ;
165 registerObject<TH1F>("cutflow", cutflow) ;
166
167 auto clusterTime = new TH1F("clusterTime", ";Electron ECL cluster time [ns]; number of ECL clusters", nbins, min_t, max_t) ;
168 registerObject<TH1F>("clusterTime", clusterTime) ;
169
170 auto clusterTime_cid = new TH2F("clusterTime_cid",
171 ";crystal Cell ID ;Electron ECL cluster time [ns]", ECLElementNumbers::c_NCrystals, 1, ECLElementNumbers::c_NCrystals + 1, nbins,
172 min_t, max_t) ;
173 registerObject<TH2F>("clusterTime_cid", clusterTime_cid) ;
174
175 auto clusterTime_run = new TH2F("clusterTime_run",
176 ";Run number ;Electron ECL cluster time [ns]", 7000, 0, 7000, nbins, min_t, max_t) ;
177 registerObject<TH2F>("clusterTime_run", clusterTime_run) ;
178
179
180 auto clusterTimeClusterE = new TH2F("clusterTimeClusterE",
181 ";Electron cluster energy [GeV];Electron cluster time [ns]", N_E_BINS, energyBinEdges, nbins, min_t, max_t) ;
182 registerObject<TH2F>("clusterTimeClusterE", clusterTimeClusterE) ;
183
184 auto dt99_clusterE = new TH2F("dt99_clusterE",
185 ";Electron cluster energy [GeV];dt99 [ns]", N_E_BINS, energyBinEdges, nbins, 0, max_t) ;
186 registerObject<TH2F>("dt99_clusterE", dt99_clusterE) ;
187
188
189 auto eventT0 = new TH1F("eventT0", ";event t0 [ns]; number of events", nbins, min_t, max_t) ;
190 registerObject<TH1F>("eventT0", eventT0) ;
191
192 auto eventT0Detector = new TH1F("eventT0Detector",
193 "detector used for eventT0 (SVD=2, CDC=4, TOP=8, ECL=32);detector number; number of events", 48, 0, 48) ;
194 registerObject<TH1F>("eventT0Detector", eventT0Detector) ;
195
196 auto clusterTimeE0E1diff = new TH1F("clusterTimeE0E1diff",
197 ";ECL cluster time of max E electron - ECL cluster time of 2nd max E electron [ns]; number of electron ECL cluster time differences",
198 nbins, min_t, max_t) ;
199 registerObject<TH1F>("clusterTimeE0E1diff", clusterTimeE0E1diff) ;
200
201
202 //=== Required data objects
203 tracks.isRequired() ;
204 m_eclClusterArray.isRequired() ;
205 m_eclCalDigitArray.isRequired() ;
206
207
208 B2INFO("skipTrgSel = " << skipTrgSel);
209
210}
211
213{
214 int cutIndexPassed = 0;
215 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
216 B2DEBUG(22, "Cutflow: no cuts: index = " << cutIndexPassed);
217
218
219 // --- Check the trigger skim is the type that has two tracks
220
221 /* If we skip the trigger skim selection then still fill the cutflow histogram
222 just so that the positions don't change. */
223 if (!skipTrgSel) {
224 if (!m_TrgResult.isValid()) {
225 B2WARNING("SoftwareTriggerResult required to select bhabha event is not found");
226 return;
227 }
228
229 /* Release05: bhabha_all is grand skim = bhabha+bhabhaecl+radee. We only want
230 to look at the 2 track bhabha events. */
231 const std::map<std::string, int>& fresults = m_TrgResult->getResults();
232 if (fresults.find("software_trigger_cut&skim&accept_bhabha") == fresults.end()) {
233 B2WARNING("Can't find required bhabha trigger identifier");
234 return;
235 }
236
237 const bool eBhabha = (m_TrgResult->getResult("software_trigger_cut&skim&accept_bhabha") ==
239 B2DEBUG(22, "eBhabha (trigger passed) = " << eBhabha);
240
241 if (!eBhabha) {
242 return;
243 }
244 }
245
246 /* Fill the histgram showing that the trigger skim cut passed OR that we
247 are skipping this selection. */
248 cutIndexPassed++;
249 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
250 B2DEBUG(22, "Cutflow: Trigger cut passed: index = " << cutIndexPassed);
251
252
253
254
255
256 /* Use ECLChannelMapper to get other detector indices for the crystals
257 For conversion from CellID to crate, shaper, and channel ids.
258 The initialization function automatically checks to see if the
259 object has been initialized and ifthe payload has changed and
260 thus needs updating. */
261 bool ECLchannelMapHasChanged = m_channelMapDB.hasChanged();
262 if (ECLchannelMapHasChanged) {
263 B2INFO("eclBhabhaTimeCalibrationValidationCollectorModule::collect() " << LogVar("ECLchannelMapHasChanged",
264 ECLchannelMapHasChanged));
265 if (!m_crystalMapper->initFromDB()) {
266 B2FATAL("eclBhabhaTimeCalibrationValidationCollectorModule::collect() : Can't initialize eclChannelMapper!");
267 }
268 }
269
270
271
272
273
274 B2DEBUG(29, "Finished checking if previous crystal time payload has changed");
275
276 if (m_CrateTimeDB.hasChanged()) {
277 m_CrateTime = m_CrateTimeDB->getCalibVector();
278 m_CrateTimeUnc = m_CrateTimeDB->getCalibUncVector();
279 }
280
281 B2DEBUG(25, "eclBhabhaTimeCalibrationValidationCollector:: loaded ECLCrateTimeOffset from the database"
282 << LogVar("IoV", m_CrateTimeDB.getIoV())
283 << LogVar("Checksum", m_CrateTimeDB.getChecksum()));
284
285 // Conversion coefficient from ADC ticks to nanoseconds
286 // TICKS_TO_NS ~ 0.4931 ns/clock tick
287 // 1/(4fRF) = 0.4913 ns/clock tick, where fRF is the accelerator RF frequency
288 const double TICKS_TO_NS = 1.0 / (4.0 * EclConfiguration::getRF()) * 1e3;
289
290
291 vector<float> Crate_time_ns(52, 0.0);
292 vector<float> Crate_time_unc_ns(52, 0.0);
294 // Make a crate time offset vector with an entry per crate (instead of per crystal) and convert from ADC counts to ns.
295 for (int crysID = 1; crysID <= ECLElementNumbers::c_NCrystals; crysID++) {
296 int crateID_temp = m_crystalMapper->getCrateID(crysID);
297 Crate_time_ns[crateID_temp - 1] = m_CrateTime[crysID] * TICKS_TO_NS;
298 Crate_time_unc_ns[crateID_temp - 1] = m_CrateTimeUnc[crysID] * TICKS_TO_NS;
299 }
300
301
302
303 // Storage crystal energies
305 for (auto& eclCalDigit : m_eclCalDigitArray) {
306 int tempCrysID = eclCalDigit.getCellId() - 1;
307 m_EperCrys[tempCrysID] = eclCalDigit.getEnergy();
308 }
309
310
311 // Getting the event t0 using the full event t0
312
313 double evt_t0 = -1000 ;
314 double evt_t0_unc = -1000 ;
315 int evt_t0_detector = 0;
316
317 // Determine if there is an event t0 to use and then extract the information about it
318 if (m_eventT0.isOptional()) {
319 if (!m_eventT0.isValid()) {
320 return;
321 }
322 if (!m_eventT0->hasEventT0()) {
323 return;
324 } else {
325 // Overall event t0 (combination of multiple event t0s from different detectors)
326 evt_t0 = m_eventT0->getEventT0() ;
327 evt_t0_unc = m_eventT0->getEventT0Uncertainty() ;
328 if (m_eventT0->isSVDEventT0()) {evt_t0_detector += 2;}
329 if (m_eventT0->isCDCEventT0()) {evt_t0_detector += 4;}
330 if (m_eventT0->isTOPEventT0()) {evt_t0_detector += 8;}
331 if (m_eventT0->isECLEventT0()) {evt_t0_detector += 32;}
332
333 }
334 B2DEBUG(26, "Found event t0") ;
335 }
336
337
338 //---------------------------------------------------------------------
339 //..Some utilities
340 PCmsLabTransform boostrotate;
341
342 //---------------------------------------------------------------------
343 //..Track properties. Use pion (211) mass hypothesis,
344 // which is the only particle hypothesis currently available???
345 double maxp[2] = {0., 0.};
346 int maxiTrk[2] = { -1, -1};
347 int nTrkAll = tracks.getEntries() ;
348
349 int nTrkLoose = 0 ;
350 int nTrkTight = 0 ;
353 /* Loop over all the tracks to define the tight and loose selection tracks
354 We will select events with only 2 tight tracks and no additional loose tracks.
355 Tight tracks are a subset of looses tracks. */
356 for (int iTrk = 0 ; iTrk < nTrkAll ; iTrk++) {
357 // Get track biasing towards the particle being a pion based on what particle types
358 // are used for reconstruction at this stage.
359 const TrackFitResult* tempTrackFit = tracks[iTrk]->getTrackFitResultWithClosestMass(Const::pion);
360 if (not tempTrackFit) {continue ;}
361
362 // Collect track info to be used for categorizing
363 short charge = tempTrackFit->getChargeSign() ;
364 double z0 = tempTrackFit->getZ0() ;
365 double d0 = tempTrackFit->getD0() ;
366 int nCDChits = tempTrackFit->getHitPatternCDC().getNHits() ;
367 double p = tempTrackFit->getMomentum().R() ;
368
369 /* Test if loose track */
370
371 // d0 and z0 cuts
372 if (fabs(d0) > m_looseTrkD0) {
373 continue;
374 }
375 if (fabs(z0) > m_looseTrkZ0) {
376 continue;
377 }
378 // Number of hits in the CDC
379 if (nCDChits < 1) {
380 continue;
381 }
382 nTrkLoose++;
383
384
385
386 /* Test if the loose track is also a tight track */
387
388 // Number of hits in the CDC
389 if (nCDChits < 20) {
390 continue;
391 }
392 // d0 and z0 cuts
393 if (fabs(d0) > m_tightTrkD0) {
394 continue;
395 }
396 if (fabs(z0) > m_tightTrkZ0) {
397 continue;
398 }
399 nTrkTight++;
400
401 // Sorting of tight tracks. Not really required as we only want two tight tracks (at the moment) but okay.
402 //..Find the maximum p negative [0] and positive [1] tracks
403 int icharge = 0;
404 if (charge > 0) {icharge = 1;}
405 if (p > maxp[icharge]) {
406 maxp[icharge] = p;
407 maxiTrk[icharge] = iTrk;
408 }
409
410 }
411 /* After that last section the numbers of loose and tight tracks are known as well as the
412 index of the loose tracks that have the highest p negatively charged and highest p positively
413 charged tracks as measured in the centre of mass frame */
414
415
416 if (nTrkTight != 2) {
417 return;
418 }
419 // There are exactly two tight tracks
420 cutIndexPassed++;
421 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
422 B2DEBUG(22, "Cutflow: Two tight tracks: index = " << cutIndexPassed);
423
424
425 if (nTrkLoose != 2) {
426 return;
427 }
428 // There are exactly two loose tracks as well, i.e. no additional loose tracks
429 cutIndexPassed++ ;
430 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed) ;
431 B2DEBUG(22, "Cutflow: No additional loose tracks: index = " << cutIndexPassed) ;
432 /* Determine if the two tracks have the opposite electric charge.
433 We know this because the track indices stores the max pt track in [0] for negatively charged track
434 and [1] fo the positively charged track. If both are filled then both a negatively charged
435 and positively charged track were found. */
436 bool oppositelyChargedTracksPassed = maxiTrk[0] != -1 && maxiTrk[1] != -1;
437 if (!oppositelyChargedTracksPassed) {
438 return;
439 }
440 // The two tracks have the opposite electric charges.
441 cutIndexPassed++;
442 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
443 B2DEBUG(22, "Cutflow: Oppositely charged tracks: index = " << cutIndexPassed);
444
445
446
447 //---------------------------------------------------------------------
448 /* Determine associated energy clusters to each of the two tracks. Sum the energies of the
449 multiple clusters to each track and find the crystal with the maximum energy within all
450 the sets of clusters associated to the tracks. Extract the good cluster times.*/
451 double trkEClustLab[2] = {0., 0.};
452 double trkEClustCOM[2] = {0., 0.};
453 double trkpLab[2];
454 double trkpCOM[2];
455 ROOT::Math::PxPyPzEVector trkp4Lab[2];
456 ROOT::Math::PxPyPzEVector trkp4COM[2];
457
458 // Index of the cluster and the crystal that has the highest energy crystal for the two tracks
459 int numClustersPerTrack[2] = { 0, 0 };
460 double E_DIV_p[2];
461
462 vector<double> goodClustTimes ;
463 vector<double> goodClust_dt99 ;
464 vector<double> goodClustE ;
465 vector<int> goodClustMaxEcrys_cid ;
466
467 for (int icharge = 0; icharge < 2; icharge++) {
468 if (maxiTrk[icharge] > -1) {
469 B2DEBUG(22, "looping over the 2 max pt tracks");
470
471 const TrackFitResult* tempTrackFit = tracks[maxiTrk[icharge]]->getTrackFitResultWithClosestMass(Const::pion);
472 if (not tempTrackFit) {continue ;}
473
474 trkp4Lab[icharge] = tempTrackFit->get4Momentum();
475 trkp4COM[icharge] = boostrotate.rotateLabToCms() * trkp4Lab[icharge];
476 trkpLab[icharge] = trkp4Lab[icharge].P();
477 trkpCOM[icharge] = trkp4COM[icharge].P();
478
479
480 /* For each cluster associated to the current track, sum up the energies to get the total
481 energy of all clusters associated to the track and find which crystal has the highest
482 energy from all those clusters*/
483 auto eclClusterRelationsFromTracks = tracks[maxiTrk[icharge]]->getRelationsTo<ECLCluster>();
484 for (unsigned int clusterIdx = 0; clusterIdx < eclClusterRelationsFromTracks.size(); clusterIdx++) {
485
486 B2DEBUG(22, "Looking at clusters. index = " << clusterIdx);
487 auto cluster = eclClusterRelationsFromTracks[clusterIdx];
488
489 if (cluster->hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons)) {
490 numClustersPerTrack[icharge]++;
491 double eClust = cluster->getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons);
492 double electronTime = cluster->getTime();
493 bool badElectronTime = cluster->hasFailedFitTime();
494 bool badElectronTimeResolution = cluster->hasFailedTimeResolution();
495 if ((fabs(electronTime) < m_timeAbsMax) &&
496 (!badElectronTime) &&
497 (!badElectronTimeResolution)) {
498 trkEClustLab[icharge] += eClust ;
499 short cid = cluster->getMaxECellId() ;
500 goodClustMaxEcrys_cid.push_back(cid) ;
501 goodClustTimes.push_back(electronTime) ;
502 goodClust_dt99.push_back(cluster->getDeltaTime99()) ;
503 goodClustE.push_back(eClust);
504 }
505 }
506 }
507 trkEClustCOM[icharge] = trkEClustLab[icharge] * trkpCOM[icharge] / trkpLab[icharge];
508
509 // Check both electrons to see if their cluster energy / track momentum is good.
510 // The Belle II physics book shows that this is the main way of separating electrons from other particles
511 // Done in the centre of mass reference frame although I believe E/p is invariant under a boost.
512 E_DIV_p[icharge] = trkEClustCOM[icharge] / trkpCOM[icharge];
513
514 }
515 }
516 /* At the end of this section the 3-momenta magnitudes and the cluster energies are known
517 for the two saved track indices for both the lab and COM frames.
518 The crystal with the maximum energy, one associated to each track, is recorded*/
519 B2DEBUG(26, "Extracted time information and E/p for the tracks") ;
520
521
522
523 /* Cut on the number of ECL cluster connected to tracks
524
525 THIS IS DIFFERENT FROM THE CODE THAT PERFORMS THE CALIBRATIONS. THIS VALIDATIONS REQUIRES
526 THAT THERE ARE EXACTLY TWO CLUSTERS ASSOCIATED TO THE TRACKS WHILE THE CALIBRATION
527 CODE ALLOWS FOR MORE THAN ONE CLUSTER PER TRACK. THIS VALIDATION ALSO DOES NOT CUT ON THE
528 NUMBER OF EXTRA CLUSTERS NOT ASSOCIATED TO THE 2 TRACKS, WHICH IS A LOOSER CUT THAN USED
529 TO PERFORM THE CALIBRATION. */
530 long unsigned int numGoodElectronClusters_cut = 2 ;
531 if (goodClustTimes.size() != numGoodElectronClusters_cut) {
532 return ;
533 }
534 // There is exactly two ECL clusters connected to tracks in the event
535 cutIndexPassed++ ;
536 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed) ;
537 B2DEBUG(22, "Cutflow: Exactly " << numGoodElectronClusters_cut
538 << " good clusters connected to tracks: index = " << cutIndexPassed);
539
540
541 // Check both electrons to see if their cluster energy / track momentum is good.
542 // The Belle II physics book shows that this is the main way of separating electrons from other particles
543 // Done in the centre of mass reference frame although I believe E/p is invariant under a boost.
544 bool E_DIV_p_instance_passed[2] = {false, false};
545 double E_DIV_p_CUT = 0.7;
546 for (int icharge = 0; icharge < 2; icharge++) {
547 E_DIV_p_instance_passed[icharge] = E_DIV_p[icharge] > E_DIV_p_CUT;
548 }
549 if (!E_DIV_p_instance_passed[0] || !E_DIV_p_instance_passed[1]) {
550 return;
551 }
552 // E/p sufficiently large
553 cutIndexPassed++;
554 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
555 B2DEBUG(22, "Cutflow: E_i/p_i > " << E_DIV_p_CUT << ": index = " << cutIndexPassed);
556
557
558
559 // Cut on the invariant mass of the tracks in the event
560 double invMassTrk = (trkp4Lab[0] + trkp4Lab[1]).M();
561 double invMass_CUT = 0.9;
562
563 bool invMassCutsPassed = invMassTrk > (invMass_CUT * boostrotate.getCMSEnergy());
564 if (!invMassCutsPassed) {
565 return;
566 }
567 // Invariable mass of the two tracks are above the minimum
568 cutIndexPassed++;
569 getObjectPtr<TH1F>("cutflow")->Fill(cutIndexPassed);
570 B2DEBUG(22, "Cutflow: m(track 1+2) > " << invMass_CUT << "*E_COM = " << invMass_CUT << " * " << boostrotate.getCMSEnergy() <<
571 " : index = " << cutIndexPassed);
572
573
574 B2DEBUG(22, "Event passed all cuts");
575
576
577 // Fill the histogram for the event level variables
578 getObjectPtr<TH1F>("eventT0")->Fill(evt_t0) ;
579 getObjectPtr<TH1F>("eventT0Detector")->Fill(evt_t0_detector + 0.00001) ;
580
581 bool isSVDt0 = m_eventT0->isSVDEventT0();
582 bool isCDCt0 = m_eventT0->isCDCEventT0();
583 bool isECLt0 = m_eventT0->isECLEventT0();
584 string t0Detector = "UNKNOWN... WHY?";
585 if (isSVDt0) {
586 t0Detector = "SVD" ;
587 } else if (isCDCt0) {
588 t0Detector = "CDC" ;
589 } else if (isECLt0) {
590 t0Detector = "ECL" ;
591 }
592
593 B2DEBUG(26, "t0 = " << evt_t0 << " ns. t0 is from SVD?=" << isSVDt0 << ", t0 is from CDC?=" << isCDCt0 << ", t0 is from ECL?=" <<
594 isECLt0 << " t0 from " <<
595 t0Detector);
596
597
598 //=== For each good electron cluster in the processed event and fill histogram.
599 for (long unsigned int i = 0 ; i < goodClustTimes.size() ; i++) {
600 getObjectPtr<TH1F>("clusterTime")->Fill(goodClustTimes[i]) ;
601 getObjectPtr<TH2F>("clusterTime_cid")->Fill(goodClustMaxEcrys_cid[i] + 0.001, goodClustTimes[i], 1) ;
602 getObjectPtr<TH2F>("clusterTime_run")->Fill(m_EventMetaData->getRun() + 0.001, goodClustTimes[i], 1) ;
603 getObjectPtr<TH2F>("clusterTimeClusterE")->Fill(goodClustE[i], goodClustTimes[i], 1) ;
604 getObjectPtr<TH2F>("dt99_clusterE")->Fill(goodClustE[i], goodClust_dt99[i], 1) ;
605
606
607 //== Save debug TTree with detailed information if necessary.
608 if (m_saveTree) {
609
610 m_tree_time = goodClustTimes[i] ;
611 m_tree_t0 = evt_t0 ;
612 m_tree_t0_unc = evt_t0_unc ;
613 m_E_electron_clust = goodClustE[i] ;
614 m_NtightTracks = nTrkTight ;
615 m_tree_evt_num = m_EventMetaData->getEvent() ;
616 m_tree_run = m_EventMetaData->getRun() ;
617 m_tree_cid = goodClustMaxEcrys_cid[i] ;
618 m_tree_dt99 = goodClust_dt99[i] ;
619
621
622 }
623 }
624 B2DEBUG(26, "Filled cluster tree") ;
625
626 //=== Fill histogram for cluster time difference of the two electrons
627 double tDiff;
628 if (goodClustE[0] > goodClustE[1]) {
629 tDiff = goodClustTimes[0] - goodClustTimes[1];
630 } else {
631 tDiff = goodClustTimes[1] - goodClustTimes[0];
632 }
633
634 getObjectPtr<TH1F>("clusterTimeE0E1diff")->Fill(tDiff) ;
635
636
637
638 if (m_saveTree) {
639 m_tree_t0 = evt_t0 ;
640 m_tree_t0_unc = evt_t0_unc ;
641 m_tree_evt_num = m_EventMetaData->getEvent() ;
642 m_tree_run = m_EventMetaData->getRun() ;
643 m_NtightTracks = nTrkTight ;
644 m_tree_E0 = goodClustE[0] ;
645 m_tree_E1 = goodClustE[1] ;
646 m_tree_time_fromE0 = goodClustTimes[0] ;
647 m_tree_time_fromE1 = goodClustTimes[1] ;
648
649 m_dbg_tree_event->Fill() ;
650
651
652 int runNum = m_EventMetaData->getRun();
653 if (m_tree_PreviousRun != runNum) {
654 for (int icrate = 1; icrate <= 52; icrate++) {
655 m_tree_run = runNum ;
656 m_tree_crateid = icrate ;
657 m_tree_tcrate = Crate_time_ns[icrate] ;
658 m_tree_tcrate_unc = Crate_time_unc_ns[icrate] ;
659
660 m_dbg_tree_run->Fill() ;
661 }
663 }
664 }
665
666 B2DEBUG(26, "Filled event tree") ;
667
668}
Calibration collector module base class.
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
bool hasChanged()
Check whether the object has changed since the last call to hasChanged of the accessor).
ECL cluster data.
Definition: ECLCluster.h:27
@ c_nPhotons
CR is split into n photons (N1)
static double getRF()
See m_rf.
unsigned short getNHits() const
Get the total Number of CDC hits in the fit.
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
Class to hold Lorentz transformations from/to CMS and boost vector.
double getCMSEnergy() const
Returns CMS energy of e+e- (aka.
const ROOT::Math::LorentzRotation 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).
ROOT::Math::PxPyPzEVector get4Momentum() const
Getter for the 4Momentum at the closest approach of the track in the r/phi projection.
double getD0() const
Getter for d0.
double getZ0() const
Getter for z0.
ROOT::Math::XYZVector getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
HitPatternCDC getHitPatternCDC() const
Getter for the hit pattern in the CDC;.
int m_tree_PreviousRun
Run number for the previous run for debug TTree output.
StoreArray< ECLCluster > m_eclClusterArray
Required input array of ECLClusters.
short m_timeAbsMax
Events with abs(time) > m_timeAbsMax are excluded, mostly for histogram x-range purposes.
int m_tree_cid
ECL Cell ID (1..ECLElementNumbers::c_NCrystals) for debug TTree output.
DBObjPtr< Belle2::ECLChannelMap > m_channelMapDB
Mapper of ecl channels to various other objects, like crates.
void collect() override
Select events and crystals and accumulate histograms.
std::vector< float > m_CrateTimeUnc
uncertainty vector obtained from DB object
StoreArray< ECLCalDigit > m_eclCalDigitArray
Required input array of ECLCalDigits.
void inDefineHisto() override
Replacement for defineHisto() in CalibrationCollector modules.
std::unique_ptr< Belle2::ECL::ECLChannelMapper > m_crystalMapper
ECL object for keeping track of mapping between crystals and crates etc.
StoreObjPtr< SoftwareTriggerResult > m_TrgResult
Store array for Trigger selection.
Class to store variables with their name which were sent to the logging service.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:649
@ c_accept
Accept this event.
const int c_NCrystals
Number of crystals.
Abstract base class for different kinds of events.
STL namespace.