Belle II Software  release-05-02-19
eclMuMuECollectorModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2013 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Christopher Hearty *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 //This module
11 #include <ecl/modules/eclMuMuECollector/eclMuMuECollectorModule.h>
12 
13 //ROOT
14 #include <TH2F.h>
15 
16 //Framework
17 #include <framework/gearbox/Const.h>
18 #include <framework/dataobjects/EventMetaData.h>
19 
20 //Tracking
21 #include <tracking/dataobjects/ExtHit.h>
22 
23 //ECL
24 #include <ecl/dataobjects/ECLDigit.h>
25 #include <ecl/dataobjects/ECLCalDigit.h>
26 #include <ecl/geometry/ECLNeighbours.h>
27 #include <ecl/dbobjects/ECLCrystalCalib.h>
28 
29 //MDST
30 #include <mdst/dataobjects/Track.h>
31 #include <mdst/dataobjects/TRGSummary.h>
32 
33 using namespace std;
34 using namespace Belle2;
35 using namespace ECL;
36 
37 
38 //-----------------------------------------------------------------
39 // Register the Module
40 //-----------------------------------------------------------------
41 REG_MODULE(eclMuMuECollector)
42 
43 //-----------------------------------------------------------------
44 // Implementation
45 //-----------------------------------------------------------------
46 
47 //-----------------------------------------------------------------------------------------------------
48 
50  m_ElectronicsCalib("ECLCrystalElectronics"), m_MuMuECalib("ECLCrystalEnergyMuMu")
51 {
52  // Set module properties
53  setDescription("Calibration Collector Module for ECL single crystal energy calibration using muons");
54  setPropertyFlags(c_ParallelProcessingCertified);
55  addParam("minPairMass", m_minPairMass, "minimum invariant mass of the muon pair (GeV/c^2)", 9.0);
56  addParam("minTrackLength", m_minTrackLength, "minimum extrapolated track length in the crystal (cm)", 30.);
57  addParam("MaxNeighbourE", m_MaxNeighbourE, "maximum energy allowed in a neighbouring crystal (GeV)", 0.010);
58  addParam("thetaLabMinDeg", m_thetaLabMinDeg, "miniumum muon theta in lab (degrees)", 17.);
59  addParam("thetaLabMaxDeg", m_thetaLabMaxDeg, "maximum muon theta in lab (degrees)", 150.);
60  addParam("measureTrueEnergy", m_measureTrueEnergy, "use MC events to obtain expected energies", false);
61  addParam("requireL1", m_requireL1, "only use events that have a level 1 trigger", true);
62 }
63 
66 void eclMuMuECollectorModule::prepare()
67 {
68 
72  B2INFO("eclMuMuECollector: Experiment = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
73 
76  auto TrkPerCrysID = new TH1F("TrkPerCrysID", "track extrapolations per crystalID;crystal ID", 8736, 0, 8736);
77  registerObject<TH1F>("TrkPerCrysID", TrkPerCrysID);
78 
79  auto EnVsCrysID = new TH2F("EnVsCrysID", "Normalized energy for each crystal;crystal ID;E/Expected", 8736, 0, 8736, 120, 0.1, 2.5);
80  registerObject<TH2F>("EnVsCrysID", EnVsCrysID);
81 
82  auto ExpEvsCrys = new TH1F("ExpEvsCrys", "Sum expected energy vs crystal ID;crystal ID;Energy (GeV)", 8736, 0, 8736);
83  registerObject<TH1F>("ExpEvsCrys", ExpEvsCrys);
84 
85  auto ElecCalibvsCrys = new TH1F("ElecCalibvsCrys", "Sum electronics calib const vs crystal ID;crystal ID;calibration constant",
86  8736, 0, 8736);
87  registerObject<TH1F>("ElecCalibvsCrys", ElecCalibvsCrys);
88 
89  auto InitialCalibvsCrys = new TH1F("InitialCalibvsCrys",
90  "Sum initial muon pair calib const vs crystal ID;crystal ID;calibration constant", 8736, 0, 8736);
91  registerObject<TH1F>("InitialCalibvsCrys", InitialCalibvsCrys);
92 
93  auto CalibEntriesvsCrys = new TH1F("CalibEntriesvsCrys", "Entries in calib vs crys histograms;crystal ID;Entries per crystal", 8736,
94  0, 8736);
95  registerObject<TH1F>("CalibEntriesvsCrys", CalibEntriesvsCrys);
96 
98  auto RawDigitAmpvsCrys = new TH2F("RawDigitAmpvsCrys", "Digit Amplitude vs crystal ID;crystal ID;Amplitude", 8736, 0, 8736, 250, 0,
99  25000);
100  registerObject<TH2F>("RawDigitAmpvsCrys", RawDigitAmpvsCrys);
101 
102  auto RawDigitTimevsCrys = new TH2F("RawDigitTimevsCrys", "Digit Time vs crystal ID;crystal ID;Time", 8736, 0, 8736, 200, -2000,
103  2000);
104  registerObject<TH2F>("RawDigitTimevsCrys", RawDigitTimevsCrys);
105 
106  //..Diagnose possible cable swaps
107  auto hitCrysVsExtrapolatedCrys = new TH2F("hitCrysVsExtrapolatedCrys",
108  "Crystals with high energy vs extrapolated crystals with no energy;extrapolated crystalID;High crystalID", 8736, 0, 8736, 8736, 0,
109  8736);
110  registerObject<TH2F>("hitCrysVsExtrapolatedCrys", hitCrysVsExtrapolatedCrys);
111 
112 
113  //------------------------------------------------------------------------
115  myNeighbours4 = new ECLNeighbours("NC", 1);
116  myNeighbours8 = new ECLNeighbours("N", 1);
117 
118 
119  //------------------------------------------------------------------------
121  B2INFO("Input parameters to eclMuMuECollector:");
122  B2INFO("minPairMass: " << m_minPairMass);
123  B2INFO("minTrackLength: " << m_minTrackLength);
124  B2INFO("MaxNeighbourE: " << m_MaxNeighbourE);
125  B2INFO("thetaLabMinDeg: " << m_thetaLabMinDeg);
126  B2INFO("thetaLabMaxDeg: " << m_thetaLabMaxDeg);
127  if (m_thetaLabMinDeg < 1.) {
128  cotThetaLabMax = 9999.;
129  } else if (m_thetaLabMinDeg > 179.) {
130  cotThetaLabMax = -9999.;
131  } else {
132  double thetaLabMin = m_thetaLabMinDeg * TMath::Pi() / 180.;
133  cotThetaLabMax = 1. / tan(thetaLabMin);
134  }
135  if (m_thetaLabMaxDeg < 1.) {
136  cotThetaLabMin = 9999.;
137  } else if (m_thetaLabMaxDeg > 179.) {
138  cotThetaLabMin = -9999.;
139  } else {
140  double thetaLabMax = m_thetaLabMaxDeg * TMath::Pi() / 180.;
141  cotThetaLabMin = 1. / tan(thetaLabMax);
142  }
143  B2INFO("cotThetaLabMin: " << cotThetaLabMin);
144  B2INFO("cotThetaLabMax: " << cotThetaLabMax);
145  B2INFO("measureTrueEnergy: " << m_measureTrueEnergy);
146  B2INFO("requireL1: " << m_requireL1);
147 
149  EperCrys.resize(8736);
150 
153  if (m_ECLExpMuMuE.hasChanged()) {ExpMuMuE = m_ECLExpMuMuE->getCalibVector();}
154  if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
155  if (m_MuMuECalib.hasChanged()) {MuMuECalib = m_MuMuECalib->getCalibVector();}
156 
158  for (int ic = 1; ic < 9000; ic += 1000) {
159  B2INFO("DB constants for cellID=" << ic << ": ExpMuMuE = " << ExpMuMuE[ic - 1] << " ElectronicsCalib = " << ElectronicsCalib[ic - 1]
160  << " MuMuECalib = " << MuMuECalib[ic - 1]);
161  }
162 
164  for (int crysID = 0; crysID < 8736; crysID++) {
165  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
166  if (ExpMuMuE[crysID] == 0) {B2FATAL("eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
167  if (MuMuECalib[crysID] == 0) {B2FATAL("eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
168  }
169 
172  m_trackArray.isRequired();
173  m_eclDigitArray.isRequired();
174 
175 }
176 
177 
180 void eclMuMuECollectorModule::collect()
181 {
182 
184  if (iEvent == 0) {
185  for (int crysID = 0; crysID < 8736; crysID++) {
186  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
187  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
188  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
189  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
190  }
191  }
192 
193  if (iEvent % 10000 == 0) {B2INFO("eclMuMuECollector: iEvent = " << iEvent);}
194  iEvent++;
195 
198  bool newConst = false;
199  if (m_ECLExpMuMuE.hasChanged()) {
200  newConst = true;
201  B2INFO("ECLExpMuMuE has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
202  ExpMuMuE = m_ECLExpMuMuE->getCalibVector();
203  }
204  if (m_ElectronicsCalib.hasChanged()) {
205  newConst = true;
206  B2INFO("ECLCrystalElectronics has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
207  ElectronicsCalib = m_ElectronicsCalib->getCalibVector();
208  }
209  if (m_MuMuECalib.hasChanged()) {
210  newConst = true;
211  B2INFO("ECLCrystalEnergyMuMu has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
212  MuMuECalib = m_MuMuECalib->getCalibVector();
213  }
214 
215  if (newConst) {
216  for (int ic = 1; ic < 9000; ic += 1000) {
217  B2INFO("DB constants for cellID=" << ic << ": ExpMuMuE = " << ExpMuMuE[ic - 1] << " ElectronicsCalib = " <<
218  ElectronicsCalib[ic - 1]
219  << " MuMuECalib = " << MuMuECalib[ic - 1]);
220  }
221 
223  for (int crysID = 0; crysID < 8736; crysID++) {
224  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
225  if (ExpMuMuE[crysID] == 0) {B2FATAL("eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
226  if (MuMuECalib[crysID] == 0) {B2FATAL("eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
227  }
228  }
229 
230 
231 
234  if (m_requireL1) {
235  unsigned int L1TriggerResults = m_TRGResults->getTRGSummary(0);
236  if (L1TriggerResults == 0) {return;}
237  }
238 
239  //------------------------------------------------------------------------
241  int nTrack = m_trackArray.getEntries();
242  if (nTrack < 2) {return;}
243 
245  double maxpt[2] = {0., 0.};
246  int iTrack[2] = { -1, -1};
247  for (int it = 0; it < nTrack; it++) {
248  const TrackFitResult* temptrackFit = m_trackArray[it]->getTrackFitResult(Const::ChargedStable(211));
249  if (not temptrackFit) {continue;}
250  int imu = 0;
251  if (temptrackFit->getChargeSign() == 1) {imu = 1; }
252 
253  double temppt = temptrackFit->getTransverseMomentum();
254  double cotThetaLab = temptrackFit->getCotTheta();
255  if (temppt > maxpt[imu] && cotThetaLab > cotThetaLabMin && cotThetaLab < cotThetaLabMax) {
256  maxpt[imu] = temppt;
257  iTrack[imu] = it;
258  }
259  }
260 
262  if (iTrack[0] == -1 || iTrack[1] == -1) { return; }
263 
265  TLorentzVector mu0 = m_trackArray[iTrack[0]]->getTrackFitResult(Const::ChargedStable(211))->get4Momentum();
266  TLorentzVector mu1 = m_trackArray[iTrack[1]]->getTrackFitResult(Const::ChargedStable(211))->get4Momentum();
267  if ((mu0 + mu1).M() < m_minPairMass) { return; }
268 
269  //------------------------------------------------------------------------
271  int extCrysID[2] = { -1, -1};
272  Const::EDetector eclID = Const::EDetector::ECL;
273  for (int imu = 0; imu < 2; imu++) {
274  TVector3 temppos[2] = {};
275  int IDEnter = -99;
276  for (auto& extHit : m_trackArray[iTrack[imu]]->getRelationsTo<ExtHit>()) {
277  int pdgCode = extHit.getPdgCode();
278  Const::EDetector detectorID = extHit.getDetectorID(); // subsystem ID
279  int temp0 = extHit.getCopyID(); // ID within that subsystem; for ecl it is crystal ID
280 
282  if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_ENTER) {
283  IDEnter = temp0;
284  temppos[0] = extHit.getPosition();
285  }
286 
288  if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_EXIT && temp0 == IDEnter) {
289  temppos[1] = extHit.getPosition();
290 
292  double trackLength = (temppos[1] - temppos[0]).Mag();
293  if (trackLength > m_minTrackLength) {extCrysID[imu] = temp0;}
294  break;
295  }
296  }
297  }
298 
300  if (extCrysID[0] == -1 && extCrysID[1] == -1) { return; }
301 
302  //------------------------------------------------------------------------
304  memset(&EperCrys[0], 0, EperCrys.size()*sizeof EperCrys[0]);
305 
306  //..Record crystals with high energies to diagnose cable swaps
307  const double highEnergyThresh = 0.18; // GeV
308  std::vector<int> highECrys; // crystalIDs of crystals with high energy
309 
310  for (auto& eclDigit : m_eclDigitArray) {
311  int crysID = eclDigit.getCellId() - 1;
312  getObjectPtr<TH2F>("RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
313 
315  EperCrys[crysID] = eclDigit.getAmp() * abs(MuMuECalib[crysID]) * ElectronicsCalib[crysID];
316  if (EperCrys[crysID] > highEnergyThresh) {highECrys.push_back(crysID);}
317  if (EperCrys[crysID] > 0.01) {
318  getObjectPtr<TH2F>("RawDigitTimevsCrys")->Fill(crysID + 0.001, eclDigit.getTimeFit());
319  }
320  }
321 
323  if (m_measureTrueEnergy) {
324 
325  for (auto& eclCalDigit : m_eclCalDigitArray) {
326  int tempCrysID = eclCalDigit.getCellId() - 1;
327  EperCrys[tempCrysID] = eclCalDigit.getEnergy();
328  }
329  }
330 
331  //------------------------------------------------------------------------
334  for (int imu = 0; imu < 2; imu++) {
335  int crysID = extCrysID[imu];
336  int cellID = crysID + 1;
337  if (crysID > -1) {
338 
339  getObjectPtr<TH1F>("TrkPerCrysID")->Fill(crysID + 0.001);
340 
341  bool noNeighbourSignal = true;
342  bool highNeighourSignal = false;
343  if (cellID >= firstcellIDN4 && crysID <= lastcellIDN4) {
344  for (const auto& tempCellID : myNeighbours4->getNeighbours(cellID)) {
345  int tempCrysID = tempCellID - 1;
346  if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
347  noNeighbourSignal = false;
348  if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal = true;}
349  }
350  }
351  } else {
352  for (const auto& tempCellID : myNeighbours8->getNeighbours(cellID)) {
353  int tempCrysID = tempCellID - 1;
354  if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
355  noNeighbourSignal = false;
356  if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal = true;}
357  }
358  }
359  }
360 
362  if (noNeighbourSignal) {
363 
365  getObjectPtr<TH2F>("EnVsCrysID")->Fill(crysID + 0.001, EperCrys[crysID] / abs(ExpMuMuE[crysID]));
366  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
367  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
368  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
369  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
370  }
371 
372  //..Possible cable swap
373  if (highNeighourSignal or (noNeighbourSignal and EperCrys[crysID] < m_MaxNeighbourE)) {
374  for (auto& id : highECrys) {
375  getObjectPtr<TH2F>("hitCrysVsExtrapolatedCrys")->Fill(crysID + 0.0001, id + 0.0001);
376  }
377  }
378  }
379  }
380 }
Belle2::CalibrationCollectorModule
Calibration collector module base class.
Definition: CalibrationCollectorModule.h:44
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::eclMuMuECollectorModule
Calibration collector module that uses muon pairs to do ECL single crystal energy calibration.
Definition: eclMuMuECollectorModule.h:46
Belle2::Const::EDetector
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:44
Belle2::TrackFitResult
Values of the result of a track fit with a given particle hypothesis.
Definition: TrackFitResult.h:59
Belle2::ECL::ECLNeighbours
Class to get the neighbours for a given cell id.
Definition: ECLNeighbours.h:38
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::TrackFitResult::getTransverseMomentum
double getTransverseMomentum() const
Getter for the absolute value of the transverse momentum at the perigee.
Definition: TrackFitResult.h:140
Belle2::Const::ChargedStable
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:465