27 #include <ecl/modules/eclBhabhaTimeCalibrationValidationCollector/eclBhabhaTimeCalibrationValidationCollectorModule.h>
28 #include <framework/dataobjects/EventMetaData.h>
29 #include <framework/gearbox/Const.h>
30 #include <ecl/dbobjects/ECLCrystalCalib.h>
31 #include <ecl/dataobjects/ECLDigit.h>
32 #include <ecl/dataobjects/ECLCalDigit.h>
33 #include <ecl/dataobjects/ECLTrig.h>
34 #include <mdst/dataobjects/ECLCluster.h>
35 #include <mdst/dataobjects/Track.h>
36 #include <mdst/dataobjects/HitPatternCDC.h>
37 #include <ecl/digitization/EclConfiguration.h>
39 #include <analysis/utility/PCmsLabTransform.h>
40 #include <analysis/ClusterUtility/ClusterUtils.h>
41 #include <boost/optional.hpp>
54 REG_MODULE(eclBhabhaTimeCalibrationValidationCollector)
62 m_dbg_tree_electronClusters(0),
65 m_CrateTimeDB("ECLCrateTimeOffset"),
68 setDescription(
"This module validates the ECL cluster times");
70 addParam(
"timeAbsMax", m_timeAbsMax,
71 "Events with fabs(getTimeFit) > m_timeAbsMax "
72 "are excluded", (
short)80);
74 addParam(
"saveTree", m_saveTree,
75 "If true, TTree 'tree' with more detailed event info is saved in "
76 "the output file specified by HistoManager",
79 addParam(
"looseTrkZ0", m_looseTrkZ0,
"max Z0 for loose tracks (cm)", 10.);
80 addParam(
"tightTrkZ0", m_tightTrkZ0,
"max Z0 for tight tracks (cm)", 2.);
81 addParam(
"looseTrkD0", m_looseTrkD0,
"max D0 for loose tracks (cm)", 2.);
82 addParam(
"tightTrkD0", m_tightTrkD0,
"max D0 for tight tracks (cm)", 0.5);
83 addParam(
"skipTrgSel", skipTrgSel,
"boolean to skip the trigger skim selection",
false);
87 setPropertyFlags(c_ParallelProcessingCertified);
104 m_dbg_tree_electronClusters =
new TTree(
"tree_electronClusters",
105 "Validating crystal and crate time calibrations using electron clusters in events with lots of tracks and clusters") ;
106 m_dbg_tree_electronClusters->Branch(
"EventNum" , &m_tree_evt_num) ->SetTitle(
"Event number") ;
107 m_dbg_tree_electronClusters->Branch(
"cluster_time" , &m_tree_time) ->SetTitle(
"Cluster time t (calibrated), ns") ;
108 m_dbg_tree_electronClusters->Branch(
"clust_E" , &m_E_electron_clust) ->SetTitle(
"Electron type cluster energy, GeV") ;
109 m_dbg_tree_electronClusters->Branch(
"t0" , &m_tree_t0) ->SetTitle(
"T0, ns") ;
110 m_dbg_tree_electronClusters->Branch(
"t0_unc" , &m_tree_t0_unc) ->SetTitle(
"T0 uncertainty, ns") ;
111 m_dbg_tree_electronClusters->Branch(
"runNum" , &m_tree_run) ->SetTitle(
"Run number") ;
112 m_dbg_tree_electronClusters->Branch(
"CrystalCellID" , &m_tree_cid) ->SetTitle(
"Cell ID, 1..8736") ;
113 m_dbg_tree_electronClusters->Branch(
"dt99" , &m_tree_dt99) ->SetTitle(
"Cluster dt99, ns") ;
114 m_dbg_tree_electronClusters->SetAutoSave(10) ;
117 m_dbg_tree_event =
new TTree(
"tree_event",
118 "Validating crystal and crate time calibrations using electron clusters in events with lots of tracks and clusters") ;
119 m_dbg_tree_event->Branch(
"EventNum" , &m_tree_evt_num) ->SetTitle(
"Event number") ;
120 m_dbg_tree_event->Branch(
"t0" , &m_tree_t0) ->SetTitle(
"T0, ns") ;
121 m_dbg_tree_event->Branch(
"t0_unc" , &m_tree_t0_unc) ->SetTitle(
"T0 uncertainty, ns") ;
122 m_dbg_tree_event->Branch(
"runNum" , &m_tree_run) ->SetTitle(
"Run number") ;
123 m_dbg_tree_event->Branch(
"E0" , &m_tree_E0) ->SetTitle(
"Highest E cluster E") ;
124 m_dbg_tree_event->Branch(
"E1" , &m_tree_E1) ->SetTitle(
"2nd highest E cluster E") ;
125 m_dbg_tree_event->Branch(
"time_E0" , &m_tree_time_fromE0) ->SetTitle(
"Cluster time of highest E cluster") ;
126 m_dbg_tree_event->Branch(
"time_E1" , &m_tree_time_fromE1) ->SetTitle(
"Cluster time of 2nd highest E cluster") ;
127 m_dbg_tree_event->SetAutoSave(10) ;
131 m_dbg_tree_run =
new TTree(
"tree_run",
"Storing crate time constants") ;
132 m_dbg_tree_run->Branch(
"runNum" , &m_tree_run) ->SetTitle(
"Run number") ;
133 m_dbg_tree_run->Branch(
"crateid" , &m_tree_crateid) ->SetTitle(
"Crate ID") ;
134 m_dbg_tree_run->Branch(
"tcrate" , &m_tree_tcrate) ->SetTitle(
"Crate time") ;
135 m_dbg_tree_run->Branch(
"tcrate_unc" , &m_tree_tcrate_unc) ->SetTitle(
"Crate time uncertainty") ;
136 m_dbg_tree_run->SetAutoSave(10) ;
143 B2INFO(
"eclBhabhaTimeCalibrationValidationCollector: Experiment = " << evtMetaData->getExperiment() <<
144 " run = " << evtMetaData->getRun()) ;
149 double binSize = 2000.0 / pow(2, 12);
150 double halfBinSize = binSize / 2.0;
154 double nBinsNeg = floor((m_timeAbsMax - halfBinSize) / binSize);
155 double min_t = -nBinsNeg * binSize - halfBinSize;
156 int nbins = nBinsNeg * 2 + 1;
157 double max_t = min_t + nbins * binSize;
161 const Int_t N_E_BIN_EDGES = 64;
162 const Int_t N_E_BINS = N_E_BIN_EDGES - 1;
163 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};
166 auto cutflow =
new TH1F(
"cutflow",
" ;Cut label number ;Number of events passing cut", 10, 0, 10) ;
167 registerObject<TH1F>(
"cutflow", cutflow) ;
169 auto clusterTime =
new TH1F(
"clusterTime",
";Electron ECL cluster time [ns]; number of ECL clusters", nbins, min_t, max_t) ;
170 registerObject<TH1F>(
"clusterTime", clusterTime) ;
172 auto clusterTime_cid =
new TH2F(
"clusterTime_cid",
173 ";crystal Cell ID ;Electron ECL cluster time [ns]", 8736, 1, 8736 + 1, nbins, min_t, max_t) ;
174 registerObject<TH2F>(
"clusterTime_cid", clusterTime_cid) ;
176 auto clusterTime_run =
new TH2F(
"clusterTime_run",
177 ";Run number ;Electron ECL cluster time [ns]", 7000, 0, 7000, nbins, min_t, max_t) ;
178 registerObject<TH2F>(
"clusterTime_run", clusterTime_run) ;
181 auto clusterTimeClusterE =
new TH2F(
"clusterTimeClusterE",
182 ";Electron cluster energy [GeV];Electron cluster time [ns]", N_E_BINS, energyBinEdges, nbins, min_t, max_t) ;
183 registerObject<TH2F>(
"clusterTimeClusterE", clusterTimeClusterE) ;
185 auto dt99_clusterE =
new TH2F(
"dt99_clusterE",
186 ";Electron cluster energy [GeV];dt99 [ns]", N_E_BINS, energyBinEdges, nbins, 0, max_t) ;
187 registerObject<TH2F>(
"dt99_clusterE", dt99_clusterE) ;
190 auto eventT0 =
new TH1F(
"eventT0",
";event t0 [ns]; number of events", nbins, min_t, max_t) ;
191 registerObject<TH1F>(
"eventT0", eventT0) ;
193 auto clusterTimeE0E1diff =
new TH1F(
"clusterTimeE0E1diff",
194 ";ECL cluster time of max E electron - ECL cluster time of 2nd max E electron [ns]; number of electron ECL cluster time differences",
195 nbins, min_t, max_t) ;
196 registerObject<TH1F>(
"clusterTimeE0E1diff", clusterTimeE0E1diff) ;
200 tracks.isRequired() ;
201 m_eclClusterArray.isRequired() ;
202 m_eclCalDigitArray.isRequired() ;
205 B2INFO(
"skipTrgSel = " << skipTrgSel);
211 int cutIndexPassed = 0;
212 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed);
213 B2DEBUG(22,
"Cutflow: no cuts: index = " << cutIndexPassed);
221 if (!m_TrgResult.isValid()) {
222 B2WARNING(
"SoftwareTriggerResult required to select bhabha event is not found");
228 const std::map<std::string, int>& fresults = m_TrgResult->getResults();
229 if (fresults.find(
"software_trigger_cut&skim&accept_bhabha") == fresults.end()) {
230 B2WARNING(
"Can't find required bhabha trigger identifier");
234 const bool eBhabha = (m_TrgResult->getResult(
"software_trigger_cut&skim&accept_bhabha") ==
236 B2DEBUG(22,
"eBhabha (trigger passed) = " << eBhabha);
246 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed);
247 B2DEBUG(22,
"Cutflow: Trigger cut passed: index = " << cutIndexPassed);
258 bool ECLchannelMapHasChanged = m_channelMapDB.hasChanged();
259 if (ECLchannelMapHasChanged) {
260 B2INFO(
"eclBhabhaTimeCalibrationValidationCollectorModule::collect() " <<
LogVar(
"ECLchannelMapHasChanged",
261 ECLchannelMapHasChanged));
262 if (!m_crystalMapper->initFromDB()) {
263 B2FATAL(
"eclBhabhaTimeCalibrationValidationCollectorModule::collect() : Can't initialize eclChannelMapper!");
271 B2DEBUG(29,
"Finished checking if previous crystal time payload has changed");
273 if (m_CrateTimeDB.hasChanged()) {
274 m_CrateTime = m_CrateTimeDB->getCalibVector();
275 m_CrateTimeUnc = m_CrateTimeDB->getCalibUncVector();
278 B2DEBUG(25,
"eclBhabhaTimeCalibrationValidationCollector:: loaded ECLCrateTimeOffset from the database"
279 <<
LogVar(
"IoV", m_CrateTimeDB.getIoV())
280 <<
LogVar(
"Checksum", m_CrateTimeDB.getChecksum()));
288 vector<float> Crate_time_ns(52, 0.0);
289 vector<float> Crate_time_unc_ns(52, 0.0);
292 for (
int crysID = 1; crysID <= 8736; crysID++) {
293 int crateID_temp = m_crystalMapper->getCrateID(crysID);
294 Crate_time_ns[crateID_temp - 1] = m_CrateTime[crysID] * TICKS_TO_NS;
295 Crate_time_unc_ns[crateID_temp - 1] = m_CrateTimeUnc[crysID] * TICKS_TO_NS;
301 m_EperCrys.resize(8736);
302 for (
auto& eclCalDigit : m_eclCalDigitArray) {
303 int tempCrysID = eclCalDigit.getCellId() - 1;
304 m_EperCrys[tempCrysID] = eclCalDigit.getEnergy();
310 double evt_t0 = -1000 ;
311 double evt_t0_unc = -1000 ;
314 if (m_eventT0.isOptional()) {
315 if (!m_eventT0.isValid()) {
318 if (!m_eventT0->hasEventT0()) {
322 evt_t0 = m_eventT0->getEventT0() ;
323 evt_t0_unc = m_eventT0->getEventT0Uncertainty() ;
325 B2DEBUG(26,
"Found event t0") ;
338 double maxp[2] = {0., 0.};
339 int maxiTrk[2] = { -1, -1};
340 int nTrkAll = tracks.getEntries() ;
349 for (
int iTrk = 0 ; iTrk < nTrkAll ; iTrk++) {
353 if (not tempTrackFit) {continue ;}
357 double z0 = tempTrackFit->
getZ0() ;
358 double d0 = tempTrackFit->
getD0() ;
365 if (fabs(d0) > m_looseTrkD0) {
368 if (fabs(z0) > m_looseTrkZ0) {
386 if (fabs(d0) > m_tightTrkD0) {
389 if (fabs(z0) > m_tightTrkZ0) {
397 if (charge > 0) {icharge = 1;}
398 if (p > maxp[icharge]) {
400 maxiTrk[icharge] = iTrk;
409 if (nTrkTight != 2) {
414 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed);
415 B2DEBUG(22,
"Cutflow: Two tight tracks: index = " << cutIndexPassed);
418 if (nTrkLoose != 2) {
423 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed) ;
424 B2DEBUG(22,
"Cutflow: No additional loose tracks: index = " << cutIndexPassed) ;
429 bool oppositelyChargedTracksPassed = maxiTrk[0] != -1 && maxiTrk[1] != -1;
430 if (!oppositelyChargedTracksPassed) {
435 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed);
436 B2DEBUG(22,
"Cutflow: Oppositely charged tracks: index = " << cutIndexPassed);
444 double trkEClustLab[2] = {0., 0.};
445 double trkEClustCOM[2] = {0., 0.};
448 TLorentzVector trkp4Lab[2];
449 TLorentzVector trkp4COM[2];
452 int numClustersPerTrack[2] = { 0, 0 };
455 vector<double> goodClustTimes ;
456 vector<double> goodClust_dt99 ;
457 vector<double> goodClustE ;
458 vector<int> goodClustMaxEcrys_cid ;
460 for (
int icharge = 0; icharge < 2; icharge++) {
461 if (maxiTrk[icharge] > -1) {
462 B2DEBUG(22,
"looping over the 2 max pt tracks");
465 if (not tempTrackFit) {continue ;}
468 trkp4COM[icharge] = boostrotate.
rotateLabToCms() * trkp4Lab[icharge];
469 trkpLab[icharge] = trkp4Lab[icharge].Rho();
470 trkpCOM[icharge] = trkp4COM[icharge].Rho();
476 auto eclClusterRelationsFromTracks = tracks[maxiTrk[icharge]]->getRelationsTo<
ECLCluster>();
477 for (
unsigned int clusterIdx = 0; clusterIdx < eclClusterRelationsFromTracks.size(); clusterIdx++) {
479 B2DEBUG(22,
"Looking at clusters. index = " << clusterIdx);
480 auto cluster = eclClusterRelationsFromTracks[clusterIdx];
483 numClustersPerTrack[icharge]++;
485 double electronTime = cluster->getTime();
486 bool badElectronTime = cluster->hasFailedFitTime();
487 bool badElectronTimeResolution = cluster->hasFailedTimeResolution();
488 if ((fabs(electronTime) < m_timeAbsMax) &&
489 (!badElectronTime) &&
490 (!badElectronTimeResolution)) {
491 trkEClustLab[icharge] += eClust ;
492 short cid = cluster->getMaxECellId() ;
493 goodClustMaxEcrys_cid.push_back(cid) ;
494 goodClustTimes.push_back(electronTime) ;
495 goodClust_dt99.push_back(cluster->getDeltaTime99()) ;
496 goodClustE.push_back(eClust);
500 trkEClustCOM[icharge] = trkEClustLab[icharge] * trkpCOM[icharge] / trkpLab[icharge];
505 E_DIV_p[icharge] = trkEClustCOM[icharge] / trkpCOM[icharge];
512 B2DEBUG(26,
"Extracted time information and E/p for the tracks") ;
523 long unsigned int numGoodElectronClusters_cut = 2 ;
524 if (goodClustTimes.size() != numGoodElectronClusters_cut) {
529 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed) ;
530 B2DEBUG(22,
"Cutflow: Exactly " << numGoodElectronClusters_cut
531 <<
" good clusters connected to tracks: index = " << cutIndexPassed);
537 bool E_DIV_p_instance_passed[2] = {
false,
false};
538 double E_DIV_p_CUT = 0.7;
539 for (
int icharge = 0; icharge < 2; icharge++) {
540 E_DIV_p_instance_passed[icharge] = E_DIV_p[icharge] > E_DIV_p_CUT;
542 if (!E_DIV_p_instance_passed[0] || !E_DIV_p_instance_passed[1]) {
547 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed);
548 B2DEBUG(22,
"Cutflow: E_i/p_i > " << E_DIV_p_CUT <<
": index = " << cutIndexPassed);
553 double invMassTrk = (trkp4Lab[0] + trkp4Lab[1]).M();
554 double invMass_CUT = 0.9;
556 bool invMassCutsPassed = invMassTrk > (invMass_CUT * boostrotate.
getCMSEnergy());
557 if (!invMassCutsPassed) {
562 getObjectPtr<TH1F>(
"cutflow")->Fill(cutIndexPassed);
563 B2DEBUG(22,
"Cutflow: m(track 1+2) > " << invMass_CUT <<
"*E_COM = " << invMass_CUT <<
" * " << boostrotate.
getCMSEnergy() <<
564 " : index = " << cutIndexPassed);
567 B2DEBUG(22,
"Event passed all cuts");
571 getObjectPtr<TH1F>(
"eventT0")->Fill(evt_t0) ;
573 bool isCDCt0 = (
static_cast<EventT0::EventT0Component>(*m_eventT0->getEventT0Component())).detectorSet.contains(Const::CDC);
574 bool isECLt0 = (
static_cast<EventT0::EventT0Component>(*m_eventT0->getEventT0Component())).detectorSet.contains(Const::ECL);
575 string t0Detector =
"UNKNOWN... WHY?";
578 }
else if (isECLt0) {
582 B2DEBUG(26,
"t0 = " << evt_t0 <<
" ns. t0 is from CDC?=" << isCDCt0 <<
", t0 is from ECL?=" << isECLt0 <<
" t0 from " <<
589 for (
long unsigned int i = 0 ; i < goodClustTimes.size() ; i++) {
590 getObjectPtr<TH1F>(
"clusterTime")->Fill(goodClustTimes[i]) ;
591 getObjectPtr<TH2F>(
"clusterTime_cid")->Fill(goodClustMaxEcrys_cid[i] + 0.001, goodClustTimes[i] , 1) ;
592 getObjectPtr<TH2F>(
"clusterTime_run")->Fill(evtMetaData->getRun() + 0.001, goodClustTimes[i] , 1) ;
593 getObjectPtr<TH2F>(
"clusterTimeClusterE")->Fill(goodClustE[i], goodClustTimes[i], 1) ;
594 getObjectPtr<TH2F>(
"dt99_clusterE")->Fill(goodClustE[i], goodClust_dt99[i], 1) ;
600 m_tree_time = goodClustTimes[i] ;
602 m_tree_t0_unc = evt_t0_unc ;
603 m_E_electron_clust = goodClustE[i] ;
604 m_NtightTracks = nTrkTight ;
605 m_tree_evt_num = evtMetaData->getEvent() ;
606 m_tree_run = evtMetaData->getRun() ;
607 m_tree_cid = goodClustMaxEcrys_cid[i] ;
608 m_tree_dt99 = goodClust_dt99[i] ;
610 m_dbg_tree_electronClusters->Fill() ;
614 B2DEBUG(26,
"Filled cluster tree") ;
618 if (goodClustE[0] > goodClustE[1]) {
619 tDiff = goodClustTimes[0] - goodClustTimes[1];
621 tDiff = goodClustTimes[1] - goodClustTimes[0];
624 getObjectPtr<TH1F>(
"clusterTimeE0E1diff")->Fill(tDiff) ;
630 m_tree_t0_unc = evt_t0_unc ;
631 m_tree_evt_num = evtMetaData->getEvent() ;
632 m_tree_run = evtMetaData->getRun() ;
633 m_NtightTracks = nTrkTight ;
634 m_tree_E0 = goodClustE[0] ;
635 m_tree_E1 = goodClustE[1] ;
636 m_tree_time_fromE0 = goodClustTimes[0] ;
637 m_tree_time_fromE1 = goodClustTimes[1] ;
639 m_dbg_tree_event->Fill() ;
642 int runNum = evtMetaData->getRun();
643 if (m_tree_PreviousRun != runNum) {
644 for (
int icrate = 1; icrate <= 52; icrate++) {
645 m_tree_run = runNum ;
646 m_tree_crateid = icrate ;
647 m_tree_tcrate = Crate_time_ns[icrate] ;
648 m_tree_tcrate_unc = Crate_time_unc_ns[icrate] ;
650 m_dbg_tree_run->Fill() ;
652 m_tree_PreviousRun = m_tree_run ;
656 B2DEBUG(26,
"Filled event tree") ;
Calibration collector module base class.
Class to provide momentum-related information from ECLClusters.
const TVector3 GetIPPosition()
Returns default IP position from beam parameters.
static const ChargedStable pion
charged pion particle
DB object to store correspondence table of type (Crate id, ShaperDSP id, Channel id) <-> (ECL CellID)
@ c_nPhotons
CR is split into n photons (N1)
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.
Type-safe access to single objects in the data store.
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;.
This module generates 'TimevsCrys' histogram to later (in eclBhabhaTAlgorithm) find time offset from ...
virtual ~eclBhabhaTimeCalibrationValidationCollectorModule()
Module destructor.
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.
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.
@ c_accept
Accept this event.
Abstract base class for different kinds of events.
Structure for storing the extracted event t0s together with its detector and its uncertainty.