Belle II Software  release-08-01-10
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 
9 /* Own header. */
10 #include <ecl/modules/eclMuMuECollector/eclMuMuECollectorModule.h>
11 
12 /* ECL headers. */
13 #include <ecl/dataobjects/ECLDigit.h>
14 #include <ecl/dataobjects/ECLElementNumbers.h>
15 #include <ecl/dbobjects/ECLCrystalCalib.h>
16 #include <ecl/geometry/ECLNeighbours.h>
17 
18 /* Basf2 headers. */
19 #include <framework/dataobjects/EventMetaData.h>
20 #include <framework/gearbox/Const.h>
21 #include <mdst/dataobjects/ECLCluster.h>
22 #include <mdst/dataobjects/Track.h>
23 #include <mdst/dataobjects/TRGSummary.h>
24 #include <tracking/dataobjects/ExtHit.h>
25 
26 /* ROOT headers. */
27 #include <TH2F.h>
28 
29 using namespace std;
30 using namespace Belle2;
31 using namespace ECL;
32 
33 
34 //-----------------------------------------------------------------
35 // Register the Module
36 //-----------------------------------------------------------------
37 REG_MODULE(eclMuMuECollector);
38 
39 //-----------------------------------------------------------------
40 // Implementation
41 //-----------------------------------------------------------------
42 
43 //-----------------------------------------------------------------------------------------------------
44 
45 eclMuMuECollectorModule::eclMuMuECollectorModule() : CalibrationCollectorModule(), m_ECLExpMuMuE("ECLExpMuMuE"),
46  m_ElectronicsCalib("ECLCrystalElectronics"), m_MuMuECalib("ECLCrystalEnergyMuMu"), m_CrystalEnergy("ECLCrystalEnergy")
47 {
48  // Set module properties
49  setDescription("Calibration Collector Module for ECL single crystal energy calibration using muons");
51  addParam("minPairMass", m_minPairMass, "minimum invariant mass of the muon pair (GeV/c^2)", 9.0);
52  addParam("minTrackLength", m_minTrackLength, "minimum extrapolated track length in the crystal (cm)", 30.);
53  addParam("MaxNeighbourE", m_MaxNeighbourE, "maximum energy allowed in a neighbouring crystal (GeV)", 0.010);
54  addParam("thetaLabMinDeg", m_thetaLabMinDeg, "miniumum muon theta in lab (degrees)", 17.);
55  addParam("thetaLabMaxDeg", m_thetaLabMaxDeg, "maximum muon theta in lab (degrees)", 150.);
56  addParam("measureTrueEnergy", m_measureTrueEnergy, "use MC events to obtain expected energies", false);
57  addParam("requireL1", m_requireL1, "only use events that have a level 1 trigger", true);
58 }
59 
63 {
64 
68  B2INFO("eclMuMuECollector: Experiment = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
69 
72  auto TrkPerCrysID = new TH1F("TrkPerCrysID", "track extrapolations per crystalID;crystal ID", ECLElementNumbers::c_NCrystals, 0,
74  registerObject<TH1F>("TrkPerCrysID", TrkPerCrysID);
75 
76  auto EnVsCrysID = new TH2F("EnVsCrysID", "Normalized energy for each crystal;crystal ID;E/Expected", ECLElementNumbers::c_NCrystals,
77  0, ECLElementNumbers::c_NCrystals, 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)",
82  registerObject<TH1F>("ExpEvsCrys", ExpEvsCrys);
83 
84  auto ElecCalibvsCrys = new TH1F("ElecCalibvsCrys", "Sum electronics calib const vs crystal ID;crystal ID;calibration constant",
86  registerObject<TH1F>("ElecCalibvsCrys", ElecCalibvsCrys);
87 
88  auto InitialCalibvsCrys = new TH1F("InitialCalibvsCrys",
89  "Sum initial muon pair calib const vs crystal ID;crystal ID;calibration constant", ECLElementNumbers::c_NCrystals, 0,
91  registerObject<TH1F>("InitialCalibvsCrys", InitialCalibvsCrys);
92 
93  auto CalibEntriesvsCrys = new TH1F("CalibEntriesvsCrys", "Entries in calib vs crys histograms;crystal ID;Entries per crystal",
96  registerObject<TH1F>("CalibEntriesvsCrys", CalibEntriesvsCrys);
97 
99  auto RawDigitAmpvsCrys = new TH2F("RawDigitAmpvsCrys", "Digit Amplitude vs crystal ID;crystal ID;Amplitude",
101  25000);
102  registerObject<TH2F>("RawDigitAmpvsCrys", RawDigitAmpvsCrys);
103 
104  auto RawDigitTimevsCrys = new TH2F("RawDigitTimevsCrys", "Digit Time vs crystal ID;crystal ID;Time", ECLElementNumbers::c_NCrystals,
105  0, ECLElementNumbers::c_NCrystals, 200, -2000,
106  2000);
107  registerObject<TH2F>("RawDigitTimevsCrys", RawDigitTimevsCrys);
108 
109  //..Diagnose possible cable swaps
110  auto hitCrysVsExtrapolatedCrys = new TH2F("hitCrysVsExtrapolatedCrys",
111  "Crystals with high energy vs extrapolated crystals with no energy;extrapolated crystalID;High crystalID",
114  registerObject<TH2F>("hitCrysVsExtrapolatedCrys", hitCrysVsExtrapolatedCrys);
115 
116 
117  //------------------------------------------------------------------------
119  myNeighbours4 = new ECLNeighbours("NC", 1);
120  myNeighbours8 = new ECLNeighbours("N", 1);
121 
122 
123  //------------------------------------------------------------------------
125  B2INFO("Input parameters to eclMuMuECollector:");
126  B2INFO("minPairMass: " << m_minPairMass);
127  B2INFO("minTrackLength: " << m_minTrackLength);
128  B2INFO("MaxNeighbourE: " << m_MaxNeighbourE);
129  B2INFO("thetaLabMinDeg: " << m_thetaLabMinDeg);
130  B2INFO("thetaLabMaxDeg: " << m_thetaLabMaxDeg);
131  if (m_thetaLabMinDeg < 1.) {
132  cotThetaLabMax = 9999.;
133  } else if (m_thetaLabMinDeg > 179.) {
134  cotThetaLabMax = -9999.;
135  } else {
136  double thetaLabMin = m_thetaLabMinDeg * TMath::Pi() / 180.;
137  cotThetaLabMax = 1. / tan(thetaLabMin);
138  }
139  if (m_thetaLabMaxDeg < 1.) {
140  cotThetaLabMin = 9999.;
141  } else if (m_thetaLabMaxDeg > 179.) {
142  cotThetaLabMin = -9999.;
143  } else {
144  double thetaLabMax = m_thetaLabMaxDeg * TMath::Pi() / 180.;
145  cotThetaLabMin = 1. / tan(thetaLabMax);
146  }
147  B2INFO("cotThetaLabMin: " << cotThetaLabMin);
148  B2INFO("cotThetaLabMax: " << cotThetaLabMax);
149  B2INFO("measureTrueEnergy: " << m_measureTrueEnergy);
150  B2INFO("requireL1: " << m_requireL1);
151 
154 
157  if (m_ECLExpMuMuE.hasChanged()) {ExpMuMuE = m_ECLExpMuMuE->getCalibVector();}
158  if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
159  if (m_MuMuECalib.hasChanged()) {MuMuECalib = m_MuMuECalib->getCalibVector();}
160  if (m_CrystalEnergy.hasChanged()) {CrystalEnergy = m_CrystalEnergy->getCalibVector();}
161 
163  for (int ic = 1; ic < 9000; ic += 1000) {
164  B2INFO("DB constants for cellID=" << ic << ": ExpMuMuE = " << ExpMuMuE[ic - 1] << " ElectronicsCalib = " << ElectronicsCalib[ic - 1]
165  << " MuMuECalib = " << MuMuECalib[ic - 1]);
166  }
167 
169  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
170  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
171  if (ExpMuMuE[crysID] == 0) {B2FATAL("eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
172  if (MuMuECalib[crysID] == 0) {B2FATAL("eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
173  }
174 
177  m_trackArray.isRequired();
178  m_eclDigitArray.isRequired();
179  if (m_measureTrueEnergy) {m_eclClusterArray.isRequired();}
180 
181 }
182 
183 
187 {
188 
190  if (iEvent == 0) {
191  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
192  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
193  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
194  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
195  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
196  }
197  }
198 
199  if (iEvent % 10000 == 0) {B2INFO("eclMuMuECollector: iEvent = " << iEvent);}
200  iEvent++;
201 
204  bool newConst = false;
205  if (m_ECLExpMuMuE.hasChanged()) {
206  newConst = true;
207  B2INFO("ECLExpMuMuE has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
208  ExpMuMuE = m_ECLExpMuMuE->getCalibVector();
209  }
210  if (m_ElectronicsCalib.hasChanged()) {
211  newConst = true;
212  B2INFO("ECLCrystalElectronics has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
213  ElectronicsCalib = m_ElectronicsCalib->getCalibVector();
214  }
215  if (m_MuMuECalib.hasChanged()) {
216  newConst = true;
217  B2INFO("ECLCrystalEnergyMuMu has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
218  MuMuECalib = m_MuMuECalib->getCalibVector();
219  }
220  if (m_CrystalEnergy.hasChanged()) {
221  newConst = true;
222  B2INFO("ECLCrystalEnergy has changed, exp = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
223  CrystalEnergy = m_CrystalEnergy->getCalibVector();
224  }
225 
226  if (newConst) {
227  for (int ic = 1; ic < 9000; ic += 1000) {
228  B2INFO("DB constants for cellID=" << ic << ": ExpMuMuE = " << ExpMuMuE[ic - 1] << " ElectronicsCalib = " <<
229  ElectronicsCalib[ic - 1]
230  << " MuMuECalib = " << MuMuECalib[ic - 1]);
231  }
232 
234  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
235  if (ElectronicsCalib[crysID] <= 0) {B2FATAL("eclMuMuECollector: ElectronicsCalib = " << ElectronicsCalib[crysID] << " for crysID = " << crysID);}
236  if (ExpMuMuE[crysID] == 0) {B2FATAL("eclMuMuECollector: ExpMuMuE = 0 for crysID = " << crysID);}
237  if (MuMuECalib[crysID] == 0) {B2FATAL("eclMuMuECollector: MuMuECalib = 0 for crysID = " << crysID);}
238  }
239  }
240 
241 
242 
245  if (m_requireL1) {
246  unsigned int L1TriggerResults = m_TRGResults->getTRGSummary(0);
247  if (L1TriggerResults == 0) {return;}
248  }
249 
250  //------------------------------------------------------------------------
252  int nTrack = m_trackArray.getEntries();
253  if (nTrack < 2) {return;}
254 
256  double maxpt[2] = {0., 0.};
257  int iTrack[2] = { -1, -1};
258  for (int it = 0; it < nTrack; it++) {
259  const TrackFitResult* temptrackFit = m_trackArray[it]->getTrackFitResult(Const::ChargedStable(211));
260  if (not temptrackFit) {continue;}
261  int imu = 0;
262  if (temptrackFit->getChargeSign() == 1) {imu = 1; }
263 
264  double temppt = temptrackFit->getTransverseMomentum();
265  double cotThetaLab = temptrackFit->getCotTheta();
266  if (temppt > maxpt[imu] && cotThetaLab > cotThetaLabMin && cotThetaLab < cotThetaLabMax) {
267  maxpt[imu] = temppt;
268  iTrack[imu] = it;
269  }
270  }
271 
273  if (iTrack[0] == -1 || iTrack[1] == -1) { return; }
274 
276  ROOT::Math::PxPyPzEVector mu0 = m_trackArray[iTrack[0]]->getTrackFitResult(Const::ChargedStable(211))->get4Momentum();
277  ROOT::Math::PxPyPzEVector mu1 = m_trackArray[iTrack[1]]->getTrackFitResult(Const::ChargedStable(211))->get4Momentum();
278  if ((mu0 + mu1).M() < m_minPairMass) { return; }
279 
280  //------------------------------------------------------------------------
282  int extCrysID[2] = { -1, -1};
283  Const::EDetector eclID = Const::EDetector::ECL;
284  for (int imu = 0; imu < 2; imu++) {
285  ROOT::Math::XYZVector temppos[2] = {};
286  int IDEnter = -99;
287  for (auto& extHit : m_trackArray[iTrack[imu]]->getRelationsTo<ExtHit>()) {
288  int pdgCode = extHit.getPdgCode();
289  Const::EDetector detectorID = extHit.getDetectorID(); // subsystem ID
290  int temp0 = extHit.getCopyID(); // ID within that subsystem; for ecl it is crystal ID
291 
293  if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_ENTER) {
294  IDEnter = temp0;
295  temppos[0] = extHit.getPosition();
296  }
297 
299  if (detectorID == eclID && TMath::Abs(pdgCode) == Const::muon.getPDGCode() && extHit.getStatus() == EXT_EXIT && temp0 == IDEnter) {
300  temppos[1] = extHit.getPosition();
301 
303  double trackLength = (temppos[1] - temppos[0]).R();
304  if (trackLength > m_minTrackLength) {extCrysID[imu] = temp0;}
305  break;
306  }
307  }
308  }
309 
311  if (extCrysID[0] == -1 && extCrysID[1] == -1) { return; }
312 
313  //------------------------------------------------------------------------
315  std::fill(EperCrys.begin(), EperCrys.end(), 0); // clear array
316 
317  //..Record crystals with high energies to diagnose cable swaps
318  const double highEnergyThresh = 0.18; // GeV
319  std::vector<int> highECrys; // crystalIDs of crystals with high energy
320 
321  //..For data, use muon pair calibration; for expected energies, use ECLCrystalEnergy
322  for (auto& eclDigit : m_eclDigitArray) {
323  int crysID = eclDigit.getCellId() - 1;
324  getObjectPtr<TH2F>("RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
325 
327  float calib = abs(MuMuECalib[crysID]);
328  if (m_measureTrueEnergy) {calib = CrystalEnergy[crysID];}
329  EperCrys[crysID] = eclDigit.getAmp() * calib * ElectronicsCalib[crysID];
330  if (EperCrys[crysID] > highEnergyThresh) {highECrys.push_back(crysID);}
331  if (EperCrys[crysID] > 0.01) {
332  getObjectPtr<TH2F>("RawDigitTimevsCrys")->Fill(crysID + 0.001, eclDigit.getTimeFit());
333  }
334  }
335 
336  //------------------------------------------------------------------------
337  //..For expected energies, get the max energies crystals from the cluster. This is
338  // safer than converting the ECLDigit, since it does not require that the ECLCrystalEnergy
339  // payload used now is the same as was used when the event was generated.
340  if (m_measureTrueEnergy) {
341  for (int ic = 0; ic < m_eclClusterArray.getEntries(); ic++) {
343  int crysID = m_eclClusterArray[ic]->getMaxECellId() - 1;
344  float undoCorrection = m_eclClusterArray[ic]->getEnergyRaw() / m_eclClusterArray[ic]->getEnergy(
346  EperCrys[crysID] = undoCorrection * m_eclClusterArray[ic]->getEnergyHighestCrystal();
347  }
348  }
349  }
350 
351  //------------------------------------------------------------------------
354  for (int imu = 0; imu < 2; imu++) {
355  int crysID = extCrysID[imu];
356  int cellID = crysID + 1;
357  if (crysID > -1) {
358 
359  getObjectPtr<TH1F>("TrkPerCrysID")->Fill(crysID + 0.001);
360 
361  bool noNeighbourSignal = true;
362  bool highNeighourSignal = false;
363  if (cellID >= firstcellIDN4 && crysID <= lastcellIDN4) {
364  for (const auto& tempCellID : myNeighbours4->getNeighbours(cellID)) {
365  int tempCrysID = tempCellID - 1;
366  if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
367  noNeighbourSignal = false;
368  if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal = true;}
369  }
370  }
371  } else {
372  for (const auto& tempCellID : myNeighbours8->getNeighbours(cellID)) {
373  int tempCrysID = tempCellID - 1;
374  if (tempCellID != cellID && EperCrys[tempCrysID] > m_MaxNeighbourE) {
375  noNeighbourSignal = false;
376  if (EperCrys[tempCrysID] > highEnergyThresh) {highNeighourSignal = true;}
377  }
378  }
379  }
380 
382  if (noNeighbourSignal) {
383 
385  getObjectPtr<TH2F>("EnVsCrysID")->Fill(crysID + 0.001, EperCrys[crysID] / abs(ExpMuMuE[crysID]));
386  getObjectPtr<TH1F>("ExpEvsCrys")->Fill(crysID + 0.001, ExpMuMuE[crysID]);
387  getObjectPtr<TH1F>("ElecCalibvsCrys")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
388  getObjectPtr<TH1F>("InitialCalibvsCrys")->Fill(crysID + 0.001, MuMuECalib[crysID]);
389  getObjectPtr<TH1F>("CalibEntriesvsCrys")->Fill(crysID + 0.001);
390  }
391 
392  //..Possible cable swap
393  if (highNeighourSignal or (noNeighbourSignal and EperCrys[crysID] < m_MaxNeighbourE)) {
394  for (auto& id : highECrys) {
395  getObjectPtr<TH2F>("hitCrysVsExtrapolatedCrys")->Fill(crysID + 0.0001, id + 0.0001);
396  }
397  }
398  }
399  }
400 }
double R
typedef autogenerated by FFTW
Calibration collector module base class.
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:580
static const ChargedStable muon
muon particle
Definition: Const.h:651
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
@ c_nPhotons
CR is split into n photons (N1)
Class to get the neighbours for a given cell id.
Definition: ECLNeighbours.h:25
const std::vector< short int > & getNeighbours(short int cid) const
Return the neighbours for a given cell ID.
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
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.
StoreArray< ECLDigit > m_eclDigitArray
Required input array of eclDigits.
double m_MaxNeighbourE
maximum signal allowed in a neighbouring crystal (0.010 GeV)
bool m_requireL1
require events to satisfy a level 1 trigger (true)
DBObjPtr< ECLCrystalCalib > m_ECLExpMuMuE
Expected energies from database.
double m_minTrackLength
minimum extrapolated track length in the crystal (30 cm)
ECL::ECLNeighbours * myNeighbours8
class to return 8 nearest neighbours to crystal
StoreArray< ECLCluster > m_eclClusterArray
Required input array of ECLClusters.
StoreObjPtr< TRGSummary > m_TRGResults
DataStore TRGSummary.
std::vector< float > ExpMuMuE
vector obtained from DB object
std::vector< float > EperCrys
ECL digit energy for each crystal.
double cotThetaLabMin
Some other useful quantities.
void collect() override
Select events and crystals and accumulate histograms.
double m_minPairMass
Parameters to control the job.
StoreObjPtr< EventMetaData > m_evtMetaData
DataStore EventMetaData.
std::vector< float > ElectronicsCalib
vector obtained from DB object
int firstcellIDN4
Neighbours of each ECL crystal.
DBObjPtr< ECLCrystalCalib > m_CrystalEnergy
Existing single single calibration from DB is used to find expected E.
int lastcellIDN4
last cellID where we only need 4 neighbours
void prepare() override
Define histograms and read payloads from DB.
ECL::ECLNeighbours * myNeighbours4
class to return 4 nearest neighbours to crystal
double m_thetaLabMaxDeg
maximum muon theta in lab (150 degrees)
double m_thetaLabMinDeg
miniumum muon theta in lab (17 degrees)
std::vector< float > CrystalEnergy
vector obtained from DB object
std::vector< float > MuMuECalib
vector obtained from DB object
DBObjPtr< ECLCrystalCalib > m_MuMuECalib
Existing single muon pair calibration from DB; will be updated by CAF.
DBObjPtr< ECLCrystalCalib > m_ElectronicsCalib
Electronics calibration from database.
bool m_measureTrueEnergy
use eclCalDigit to determine MC deposited energy (false)
double cotThetaLabMax
m_thetaLabMaxDeg converted to cotangent
StoreArray< Track > m_trackArray
Required arrays.
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double tan(double a)
tan for double
Definition: beamHelpers.h:31
const int c_NCrystals
Number of crystals.
Abstract base class for different kinds of events.