Belle II Software  release-06-02-00
eclMuMuECollectorModule.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 //This module
9 #include <ecl/modules/eclMuMuECollector/eclMuMuECollectorModule.h>
10 
11 //ROOT
12 #include <TH2F.h>
13 
14 //Framework
15 #include <framework/gearbox/Const.h>
16 #include <framework/dataobjects/EventMetaData.h>
17 
18 //Tracking
19 #include <tracking/dataobjects/ExtHit.h>
20 
21 //ECL
22 #include <ecl/dataobjects/ECLDigit.h>
23 #include <ecl/geometry/ECLNeighbours.h>
24 #include <ecl/dbobjects/ECLCrystalCalib.h>
25 
26 //MDST
27 #include <mdst/dataobjects/Track.h>
28 #include <mdst/dataobjects/TRGSummary.h>
29 #include <mdst/dataobjects/ECLCluster.h>
30 
31 using namespace std;
32 using namespace Belle2;
33 using namespace ECL;
34 
35 
36 //-----------------------------------------------------------------
37 // Register the Module
38 //-----------------------------------------------------------------
39 REG_MODULE(eclMuMuECollector)
40 
41 //-----------------------------------------------------------------
42 // Implementation
43 //-----------------------------------------------------------------
44 
45 //-----------------------------------------------------------------------------------------------------
46 
48  m_ElectronicsCalib("ECLCrystalElectronics"), m_MuMuECalib("ECLCrystalEnergyMuMu"), m_CrystalEnergy("ECLCrystalEnergy")
49 {
50  // Set module properties
51  setDescription("Calibration Collector Module for ECL single crystal energy calibration using muons");
52  setPropertyFlags(c_ParallelProcessingCertified);
53  addParam("minPairMass", m_minPairMass, "minimum invariant mass of the muon pair (GeV/c^2)", 9.0);
54  addParam("minTrackLength", m_minTrackLength, "minimum extrapolated track length in the crystal (cm)", 30.);
55  addParam("MaxNeighbourE", m_MaxNeighbourE, "maximum energy allowed in a neighbouring crystal (GeV)", 0.010);
56  addParam("thetaLabMinDeg", m_thetaLabMinDeg, "miniumum muon theta in lab (degrees)", 17.);
57  addParam("thetaLabMaxDeg", m_thetaLabMaxDeg, "maximum muon theta in lab (degrees)", 150.);
58  addParam("measureTrueEnergy", m_measureTrueEnergy, "use MC events to obtain expected energies", false);
59  addParam("requireL1", m_requireL1, "only use events that have a level 1 trigger", true);
60 }
61 
64 void eclMuMuECollectorModule::prepare()
65 {
66 
70  B2INFO("eclMuMuECollector: Experiment = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
71 
74  auto TrkPerCrysID = new TH1F("TrkPerCrysID", "track extrapolations per crystalID;crystal ID", 8736, 0, 8736);
75  registerObject<TH1F>("TrkPerCrysID", TrkPerCrysID);
76 
77  auto EnVsCrysID = new TH2F("EnVsCrysID", "Normalized energy for each crystal;crystal ID;E/Expected", 8736, 0, 8736, 240, 0.1, 2.5);
78  registerObject<TH2F>("EnVsCrysID", EnVsCrysID);
79 
80  auto ExpEvsCrys = new TH1F("ExpEvsCrys", "Sum expected energy vs crystal ID;crystal ID;Energy (GeV)", 8736, 0, 8736);
81  registerObject<TH1F>("ExpEvsCrys", ExpEvsCrys);
82 
83  auto ElecCalibvsCrys = new TH1F("ElecCalibvsCrys", "Sum electronics calib const vs crystal ID;crystal ID;calibration constant",
84  8736, 0, 8736);
85  registerObject<TH1F>("ElecCalibvsCrys", ElecCalibvsCrys);
86 
87  auto InitialCalibvsCrys = new TH1F("InitialCalibvsCrys",
88  "Sum initial muon pair calib const vs crystal ID;crystal ID;calibration constant", 8736, 0, 8736);
89  registerObject<TH1F>("InitialCalibvsCrys", InitialCalibvsCrys);
90 
91  auto CalibEntriesvsCrys = new TH1F("CalibEntriesvsCrys", "Entries in calib vs crys histograms;crystal ID;Entries per crystal", 8736,
92  0, 8736);
93  registerObject<TH1F>("CalibEntriesvsCrys", CalibEntriesvsCrys);
94 
96  auto RawDigitAmpvsCrys = new TH2F("RawDigitAmpvsCrys", "Digit Amplitude vs crystal ID;crystal ID;Amplitude", 8736, 0, 8736, 250, 0,
97  25000);
98  registerObject<TH2F>("RawDigitAmpvsCrys", RawDigitAmpvsCrys);
99 
100  auto RawDigitTimevsCrys = new TH2F("RawDigitTimevsCrys", "Digit Time vs crystal ID;crystal ID;Time", 8736, 0, 8736, 200, -2000,
101  2000);
102  registerObject<TH2F>("RawDigitTimevsCrys", RawDigitTimevsCrys);
103 
104  //..Diagnose possible cable swaps
105  auto hitCrysVsExtrapolatedCrys = new TH2F("hitCrysVsExtrapolatedCrys",
106  "Crystals with high energy vs extrapolated crystals with no energy;extrapolated crystalID;High crystalID", 8736, 0, 8736, 8736, 0,
107  8736);
108  registerObject<TH2F>("hitCrysVsExtrapolatedCrys", hitCrysVsExtrapolatedCrys);
109 
110 
111  //------------------------------------------------------------------------
113  myNeighbours4 = new ECLNeighbours("NC", 1);
114  myNeighbours8 = new ECLNeighbours("N", 1);
115 
116 
117  //------------------------------------------------------------------------
119  B2INFO("Input parameters to eclMuMuECollector:");
120  B2INFO("minPairMass: " << m_minPairMass);
121  B2INFO("minTrackLength: " << m_minTrackLength);
122  B2INFO("MaxNeighbourE: " << m_MaxNeighbourE);
123  B2INFO("thetaLabMinDeg: " << m_thetaLabMinDeg);
124  B2INFO("thetaLabMaxDeg: " << m_thetaLabMaxDeg);
125  if (m_thetaLabMinDeg < 1.) {
126  cotThetaLabMax = 9999.;
127  } else if (m_thetaLabMinDeg > 179.) {
128  cotThetaLabMax = -9999.;
129  } else {
130  double thetaLabMin = m_thetaLabMinDeg * TMath::Pi() / 180.;
131  cotThetaLabMax = 1. / tan(thetaLabMin);
132  }
133  if (m_thetaLabMaxDeg < 1.) {
134  cotThetaLabMin = 9999.;
135  } else if (m_thetaLabMaxDeg > 179.) {
136  cotThetaLabMin = -9999.;
137  } else {
138  double thetaLabMax = m_thetaLabMaxDeg * TMath::Pi() / 180.;
139  cotThetaLabMin = 1. / tan(thetaLabMax);
140  }
141  B2INFO("cotThetaLabMin: " << cotThetaLabMin);
142  B2INFO("cotThetaLabMax: " << cotThetaLabMax);
143  B2INFO("measureTrueEnergy: " << m_measureTrueEnergy);
144  B2INFO("requireL1: " << m_requireL1);
145 
147  EperCrys.resize(8736);
148 
151  if (m_ECLExpMuMuE.hasChanged()) {ExpMuMuE = m_ECLExpMuMuE->getCalibVector();}
152  if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
153  if (m_MuMuECalib.hasChanged()) {MuMuECalib = m_MuMuECalib->getCalibVector();}
154  if (m_CrystalEnergy.hasChanged()) {CrystalEnergy = m_CrystalEnergy->getCalibVector();}
155 
157  for (int ic = 1; ic < 9000; ic += 1000) {
158  B2INFO("DB constants for cellID=" << ic << ": ExpMuMuE = " << ExpMuMuE[ic - 1] << " ElectronicsCalib = " << ElectronicsCalib[ic - 1]
159  << " MuMuECalib = " << MuMuECalib[ic - 1]);
160  }
161 
163  for (int crysID = 0; crysID < 8736; crysID++) {
164  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
165  if (ExpMuMuE[crysID] == 0) {B2FATAL("eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
166  if (MuMuECalib[crysID] == 0) {B2FATAL("eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
167  }
168 
171  m_trackArray.isRequired();
172  m_eclDigitArray.isRequired();
173  if (m_measureTrueEnergy) {m_eclClusterArray.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  if (m_CrystalEnergy.hasChanged()) {
215  newConst = true;
216  B2INFO("ECLCrystalEnergy has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
217  CrystalEnergy = m_CrystalEnergy->getCalibVector();
218  }
219 
220  if (newConst) {
221  for (int ic = 1; ic < 9000; ic += 1000) {
222  B2INFO("DB constants for cellID=" << ic << ": ExpMuMuE = " << ExpMuMuE[ic - 1] << " ElectronicsCalib = " <<
223  ElectronicsCalib[ic - 1]
224  << " MuMuECalib = " << MuMuECalib[ic - 1]);
225  }
226 
228  for (int crysID = 0; crysID < 8736; crysID++) {
229  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
230  if (ExpMuMuE[crysID] == 0) {B2FATAL("eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
231  if (MuMuECalib[crysID] == 0) {B2FATAL("eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
232  }
233  }
234 
235 
236 
239  if (m_requireL1) {
240  unsigned int L1TriggerResults = m_TRGResults->getTRGSummary(0);
241  if (L1TriggerResults == 0) {return;}
242  }
243 
244  //------------------------------------------------------------------------
246  int nTrack = m_trackArray.getEntries();
247  if (nTrack < 2) {return;}
248 
250  double maxpt[2] = {0., 0.};
251  int iTrack[2] = { -1, -1};
252  for (int it = 0; it < nTrack; it++) {
253  const TrackFitResult* temptrackFit = m_trackArray[it]->getTrackFitResult(Const::ChargedStable(211));
254  if (not temptrackFit) {continue;}
255  int imu = 0;
256  if (temptrackFit->getChargeSign() == 1) {imu = 1; }
257 
258  double temppt = temptrackFit->getTransverseMomentum();
259  double cotThetaLab = temptrackFit->getCotTheta();
260  if (temppt > maxpt[imu] && cotThetaLab > cotThetaLabMin && cotThetaLab < cotThetaLabMax) {
261  maxpt[imu] = temppt;
262  iTrack[imu] = it;
263  }
264  }
265 
267  if (iTrack[0] == -1 || iTrack[1] == -1) { return; }
268 
270  TLorentzVector mu0 = m_trackArray[iTrack[0]]->getTrackFitResult(Const::ChargedStable(211))->get4Momentum();
271  TLorentzVector mu1 = m_trackArray[iTrack[1]]->getTrackFitResult(Const::ChargedStable(211))->get4Momentum();
272  if ((mu0 + mu1).M() < m_minPairMass) { return; }
273 
274  //------------------------------------------------------------------------
276  int extCrysID[2] = { -1, -1};
277  Const::EDetector eclID = Const::EDetector::ECL;
278  for (int imu = 0; imu < 2; imu++) {
279  TVector3 temppos[2] = {};
280  int IDEnter = -99;
281  for (auto& extHit : m_trackArray[iTrack[imu]]->getRelationsTo<ExtHit>()) {
282  int pdgCode = extHit.getPdgCode();
283  Const::EDetector detectorID = extHit.getDetectorID(); // subsystem ID
284  int temp0 = extHit.getCopyID(); // ID within that subsystem; for ecl it is crystal ID
285 
287  if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_ENTER) {
288  IDEnter = temp0;
289  temppos[0] = extHit.getPosition();
290  }
291 
293  if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_EXIT && temp0 == IDEnter) {
294  temppos[1] = extHit.getPosition();
295 
297  double trackLength = (temppos[1] - temppos[0]).Mag();
298  if (trackLength > m_minTrackLength) {extCrysID[imu] = temp0;}
299  break;
300  }
301  }
302  }
303 
305  if (extCrysID[0] == -1 && extCrysID[1] == -1) { return; }
306 
307  //------------------------------------------------------------------------
309  std::fill(EperCrys.begin(), EperCrys.end(), 0); // clear array
310 
311  //..Record crystals with high energies to diagnose cable swaps
312  const double highEnergyThresh = 0.18; // GeV
313  std::vector<int> highECrys; // crystalIDs of crystals with high energy
314 
315  //..For data, use muon pair calibration; for expected energies, use ECLCrystalEnergy
316  for (auto& eclDigit : m_eclDigitArray) {
317  int crysID = eclDigit.getCellId() - 1;
318  getObjectPtr<TH2F>("RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
319 
321  float calib = abs(MuMuECalib[crysID]);
322  if (m_measureTrueEnergy) {calib = CrystalEnergy[crysID];}
323  EperCrys[crysID] = eclDigit.getAmp() * calib * ElectronicsCalib[crysID];
324  if (EperCrys[crysID] > highEnergyThresh) {highECrys.push_back(crysID);}
325  if (EperCrys[crysID] > 0.01) {
326  getObjectPtr<TH2F>("RawDigitTimevsCrys")->Fill(crysID + 0.001, eclDigit.getTimeFit());
327  }
328  }
329 
330  //------------------------------------------------------------------------
331  //..For expected energies, get the max energies crystals from the cluster. This is
332  // safer than converting the ECLDigit, since it does not require that the ECLCrystalEnergy
333  // payload used now is the same as was used when the event was generated.
334  if (m_measureTrueEnergy) {
335  for (int ic = 0; ic < m_eclClusterArray.getEntries(); ic++) {
336  if (m_eclClusterArray[ic]->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) {
337  int crysID = m_eclClusterArray[ic]->getMaxECellId() - 1;
338  float undoCorrection = m_eclClusterArray[ic]->getEnergyRaw() / m_eclClusterArray[ic]->getEnergy(
339  ECLCluster::EHypothesisBit::c_nPhotons);
340  EperCrys[crysID] = undoCorrection * m_eclClusterArray[ic]->getEnergyHighestCrystal();
341  }
342  }
343  }
344 
345  //------------------------------------------------------------------------
348  for (int imu = 0; imu < 2; imu++) {
349  int crysID = extCrysID[imu];
350  int cellID = crysID + 1;
351  if (crysID > -1) {
352 
353  getObjectPtr<TH1F>("TrkPerCrysID")->Fill(crysID + 0.001);
354 
355  bool noNeighbourSignal = true;
356  bool highNeighourSignal = false;
357  if (cellID >= firstcellIDN4 && crysID <= lastcellIDN4) {
358  for (const auto& tempCellID : myNeighbours4->getNeighbours(cellID)) {
359  int tempCrysID = tempCellID - 1;
360  if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
361  noNeighbourSignal = false;
362  if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal = true;}
363  }
364  }
365  } else {
366  for (const auto& tempCellID : myNeighbours8->getNeighbours(cellID)) {
367  int tempCrysID = tempCellID - 1;
368  if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
369  noNeighbourSignal = false;
370  if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal = true;}
371  }
372  }
373  }
374 
376  if (noNeighbourSignal) {
377 
379  getObjectPtr<TH2F>("EnVsCrysID")->Fill(crysID + 0.001, EperCrys[crysID] / abs(ExpMuMuE[crysID]));
380  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
381  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
382  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
383  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
384  }
385 
386  //..Possible cable swap
387  if (highNeighourSignal or (noNeighbourSignal and EperCrys[crysID] < m_MaxNeighbourE)) {
388  for (auto& id : highECrys) {
389  getObjectPtr<TH2F>("hitCrysVsExtrapolatedCrys")->Fill(crysID + 0.0001, id + 0.0001);
390  }
391  }
392  }
393  }
394 }
Calibration collector module base class.
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:470
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
Class to get the neighbours for a given cell id.
Definition: ECLNeighbours.h:23
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
double getCotTheta() const
Getter for tanLambda with CDF naming convention.
double getTransverseMomentum() const
Getter for the absolute value of the transverse momentum at the perigee.
Calibration collector module that uses muon pairs to do ECL single crystal energy calibration.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.