Belle II Software  release-08-01-10
eclCosmicECollectorModule.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/eclCosmicECollector/eclCosmicECollectorModule.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/ECLGeometryPar.h>
17 #include <ecl/geometry/ECLNeighbours.h>
18 
19 /* Basf2 headers. */
20 #include <framework/dataobjects/EventMetaData.h>
21 #include <trg/ecl/TrgEclMapping.h>
22 
23 /* ROOT headers. */
24 #include <TH2F.h>
25 
26 using namespace std;
27 using namespace Belle2;
28 using namespace ECL;
29 
30 
32 // Register the Module
34 REG_MODULE(eclCosmicECollector);
35 
37 // Implementation
42 eclCosmicECollectorModule::eclCosmicECollectorModule() : CalibrationCollectorModule(), m_ECLExpCosmicESame("ECLExpCosmicESame"),
43  m_ECLExpCosmicEDifferent("ECLExpCosmicEDifferent"), m_ElectronicsCalib("ECLCrystalElectronics"),
44  m_CosmicECalib("ECLCrystalEnergyCosmic")
45 {
47  setDescription("Calibration Collector Module for ECL single crystal energy calibration using cosmic rays");
49  addParam("minCrysE", m_minCrysE, "Minimum energy in GeV for a crystal to be considered hit", 0.010);
50  addParam("mockupL1", m_mockupL1, "Calculate energy per trigger cell in lieu of trigger simulation", false);
51  addParam("trigThreshold", m_trigThreshold, "Minimum energy in GeV per trigger cell to mock up L1 trigger", 0.1);
52 }
53 
54 
58 {
59  B2INFO("eclCosmicECollector: Experiment = " << m_evtMetaData->getExperiment() << " run = " << m_evtMetaData->getRun());
60 
62  m_eclDigitArray.isRequired();
63 
66  auto EnvsCrysSameRing = new TH2F("EnvsCrysSameRing", "Normalized energy vs crystal ID, same theta ring;crystal ID;E/Expected",
68  0, ECLElementNumbers::c_NCrystals, 99, .025, 2.5);
69  registerObject<TH2F>("EnvsCrysSameRing", EnvsCrysSameRing);
70 
71  auto EnvsCrysDifferentRing = new TH2F("EnvsCrysDifferentRing",
72  "Normalized energy vs crystal ID, different theta rings;crystal ID;E/Expected", ECLElementNumbers::c_NCrystals, 0,
73  ECLElementNumbers::c_NCrystals, 99, .025, 2.5);
74  registerObject<TH2F>("EnvsCrysDifferentRing", EnvsCrysDifferentRing);
75 
76  auto ExpEvsCrysSameRing = new TH1F("ExpEvsCrysSameRing",
77  "Sum expected energy vs crystal ID, same theta ring;crystal ID;Energy (GeV)", ECLElementNumbers::c_NCrystals, 0,
79  registerObject<TH1F>("ExpEvsCrysSameRing", ExpEvsCrysSameRing);
80 
81  auto ExpEvsCrysDifferentRing = new TH1F("ExpEvsCrysDifferentRing",
82  "Sum expected energy vs crystal ID, different theta rings;crystal ID;Energy (GeV)", ECLElementNumbers::c_NCrystals, 0,
84  registerObject<TH1F>("ExpEvsCrysDifferentRing", ExpEvsCrysDifferentRing);
85 
86  auto ElecCalibvsCrysSameRing = new TH1F("ElecCalibvsCrysSameRing",
87  "Sum electronics calib const vs crystal ID, same theta ring;crystal ID", ECLElementNumbers::c_NCrystals, 0,
89  registerObject<TH1F>("ElecCalibvsCrysSameRing", ElecCalibvsCrysSameRing);
90 
91  auto ElecCalibvsCrysDifferentRing = new TH1F("ElecCalibvsCrysDifferentRing",
92  "Sum electronics calib const vs crystal ID, different theta rings;crystal ID", ECLElementNumbers::c_NCrystals, 0,
94  registerObject<TH1F>("ElecCalibvsCrysDifferentRing", ElecCalibvsCrysDifferentRing);
95 
96  auto InitialCalibvsCrysSameRing = new TH1F("InitialCalibvsCrysSameRing",
97  "Sum initial cosmic calib const vs crystal ID, same theta ring;crystal ID", ECLElementNumbers::c_NCrystals, 0,
99  registerObject<TH1F>("InitialCalibvsCrysSameRing", InitialCalibvsCrysSameRing);
100 
101  auto InitialCalibvsCrysDifferentRing = new TH1F("InitialCalibvsCrysDifferentRing",
102  "Sum initial cosmic calib const vs crystal ID, different theta rings;crystal ID", ECLElementNumbers::c_NCrystals, 0,
104  registerObject<TH1F>("InitialCalibvsCrysDifferentRing", InitialCalibvsCrysDifferentRing);
105 
106  auto CalibEntriesvsCrysSameRing = new TH1F("CalibEntriesvsCrysSameRing",
107  "Entries in calib vs crys histograms, same theta ring;crystal ID;Entries per crystal", ECLElementNumbers::c_NCrystals, 0,
109  registerObject<TH1F>("CalibEntriesvsCrysSameRing", CalibEntriesvsCrysSameRing);
110 
111  auto CalibEntriesvsCrysDifferentRing = new TH1F("CalibEntriesvsCrysDifferentRing",
112  "Entries in calib vs crys histograms, different theta rings;crystal ID;Entries per crystal", ECLElementNumbers::c_NCrystals, 0,
114  registerObject<TH1F>("CalibEntriesvsCrysDifferentRing", CalibEntriesvsCrysDifferentRing);
115 
116  auto RawDigitAmpvsCrys = new TH2F("RawDigitAmpvsCrys", "Digit Amplitude vs crystal ID;crystal ID;Amplitude",
118  2000);
119  registerObject<TH2F>("RawDigitAmpvsCrys", RawDigitAmpvsCrys);
120 
123  B2INFO("Input parameters to eclCosmicECollector:");
124  B2INFO("trigThreshold: " << m_trigThreshold);
125  B2INFO("minCrysE: " << m_minCrysE);
126 
128  FirstSet.resize(8737);
131  EnergyPerTC.resize(576);
133 
134 
137  if (m_ECLExpCosmicESame.hasChanged()) {ExpCosmicESame = m_ECLExpCosmicESame->getCalibVector();}
138  if (m_ECLExpCosmicEDifferent.hasChanged()) {ExpCosmicEDifferent = m_ECLExpCosmicEDifferent->getCalibVector();}
139  if (m_ElectronicsCalib.hasChanged()) {ElectronicsCalib = m_ElectronicsCalib->getCalibVector();}
140  if (m_CosmicECalib.hasChanged()) {CosmicECalib = m_CosmicECalib->getCalibVector();}
141 
143  for (int ic = 1; ic < 9000; ic += 1000) {
144  B2INFO("DB constants for cellID=" << ic << ": ExpCosmicESame = " << ExpCosmicESame[ic - 1] << " ExpCosmicEDifferent = " <<
145  ExpCosmicEDifferent[ic - 1] << " ElectronicsCalib = " << ElectronicsCalib[ic - 1] << " CosmicECalib = " << CosmicECalib[ic - 1]);
146  }
147 
149  for (int ic = 0; ic < ECLElementNumbers::c_NCrystals; ic++) {
150  if (ElectronicsCalib[ic] <= 0) {B2FATAL("eclCosmicECollector: ElectronicsCalib = " << ElectronicsCalib[ic] << " for crysID = " << ic);}
151  if (ExpCosmicESame[ic] == 0) {B2FATAL("eclCosmicECollector: ExpCosmicESame = 0 for crysID = " << ic);}
152  if (ExpCosmicEDifferent[ic] == 0) {B2FATAL("eclCosmicECollector: ExpCosmicEDifferent = 0 for crysID = " << ic);}
153  if (CosmicECalib[ic] == 0) {B2FATAL("eclCosmicECollector: CosmicECalib = 0 for crysID = " << ic);}
154  }
155 
160  const short m_crystalsPerRing[69] = {
161  48, 48, 64, 64, 64, 96, 96, 96, 96, 96, 96, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 96, 96, 96, 96, 96, 64, 64, 64
162  };
163 
165  short firstCrystal[69] = {};
166  for (int it = 1; it < 69; it++) {firstCrystal[it] = firstCrystal[it - 1] + m_crystalsPerRing[it - 1];}
167 
169  std::vector<short int> ThetaIDCrys(ECLElementNumbers::c_NCrystals);
170  std::vector<short int> PhiIDCrys(ECLElementNumbers::c_NCrystals);
171  int cID = 0;
172  for (int it = 0; it < 69; it++) {
173  for (int ic = 0; ic < m_crystalsPerRing[it]; ic++) {
174  ThetaIDCrys.at(cID) = it;
175  PhiIDCrys.at(cID) = ic;
176  cID++;
177  }
178  }
179 
182  TrgEclMapping* trgecl_obj = new TrgEclMapping();
183  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
184  TCperCrys[crysID] = trgecl_obj->getTCIdFromXtalId(crysID + 1) - 1;
185  }
192  int ThetaID = 0;
193  double n2Overn0 = (double)m_crystalsPerRing[ThetaID + 2] / (double)m_crystalsPerRing[ThetaID];
194  for (int phiID = 0; phiID < m_crystalsPerRing[ThetaID]; phiID++) {
195  int crysID = firstCrystal[ThetaID] + phiID;
196 
198  int phiIDA = phiID + 1;
199  if (phiIDA == m_crystalsPerRing[ThetaID]) {phiIDA = 0;}
200  int phiIDB = phiID - 1;
201  if (phiIDB == -1) {phiIDB = m_crystalsPerRing[ThetaID] - 1;}
202  FirstSet[crysID] = CenterCrys.size();
203  CenterCrys.push_back(crysID);
204  NeighbourA.push_back(firstCrystal[ThetaID] + phiIDA);
205  NeighbourB.push_back(firstCrystal[ThetaID] + phiIDB);
206 
208  double dphiB = n2Overn0 * phiID + 0.0001;
209  phiIDB = dphiB;
210  CenterCrys.push_back(crysID);
211  NeighbourA.push_back(firstCrystal[ThetaID + 1] + phiID);
212  NeighbourB.push_back(firstCrystal[ThetaID + 2] + phiIDB);
213 
214  phiIDB++;
215  CenterCrys.push_back(crysID);
216  NeighbourA.push_back(firstCrystal[ThetaID + 1] + phiID);
217  NeighbourB.push_back(firstCrystal[ThetaID + 2] + phiIDB);
218  }
219 
224  ECLNeighbours* myNeighbours4 = new ECLNeighbours("F", 0.95);
225 
226  for (int crysID = firstCrystal[1]; crysID < firstCrystal[68]; crysID++) {
227  std::vector<short int> neighbours = myNeighbours4->getNeighbours(crysID + 1);
228 
230  int nA = -1;
231  int nB = -1;
232  std::vector<short int> nextThetaNeighbours;
233  std::vector<short int> previousThetaNeighbours;
234  for (auto& ID1 : neighbours) {
235  int temp0 = ID1 - 1;
236  if (temp0 != crysID && ThetaIDCrys[temp0] == ThetaIDCrys[crysID] && nA == -1) {
237  nA = temp0;
238  } else if (temp0 != crysID && ThetaIDCrys[temp0] == ThetaIDCrys[crysID] && nA != -1) {
239  nB = temp0;
240  }
241 
243  if (ThetaIDCrys[temp0] == ThetaIDCrys[crysID] + 1) {nextThetaNeighbours.push_back(temp0);}
244  if (ThetaIDCrys[temp0] == ThetaIDCrys[crysID] - 1) {previousThetaNeighbours.push_back(temp0);}
245  }
246 
248  if (nA >= 0 && nB >= 0) {
249  FirstSet[crysID] = CenterCrys.size();
250  CenterCrys.push_back(crysID);
251  NeighbourA.push_back(nA);
252  NeighbourB.push_back(nB);
253  } else {
254  B2FATAL("No neighbour pair with the same thetaID for crysID = " << crysID);
255  }
256 
258  for (auto& IDn : nextThetaNeighbours) {
259  for (auto& IDp : previousThetaNeighbours) {
260  CenterCrys.push_back(crysID);
261  NeighbourA.push_back(IDn);
262  NeighbourB.push_back(IDp);
263  }
264  }
265  }
266 
270  ThetaID = 68;
271  for (int phiID = 0; phiID < m_crystalsPerRing[ThetaID]; phiID++) {
272  int crysID = firstCrystal[ThetaID] + phiID;
273 
275  int phiIDA = phiID + 1;
276  if (phiIDA == m_crystalsPerRing[ThetaID]) {phiIDA = 0;}
277  int phiIDB = phiID - 1;
278  if (phiIDB == -1) {phiIDB = m_crystalsPerRing[ThetaID] - 1;}
279  FirstSet[crysID] = CenterCrys.size();
280  CenterCrys.push_back(crysID);
281  NeighbourA.push_back(firstCrystal[ThetaID] + phiIDA);
282  NeighbourB.push_back(firstCrystal[ThetaID] + phiIDB);
283 
285  CenterCrys.push_back(crysID);
286  NeighbourA.push_back(firstCrystal[ThetaID - 1] + phiID);
287  NeighbourB.push_back(firstCrystal[ThetaID - 2] + phiID);
288  }
289 
292 }
293 
294 
298 {
299 
302  if (iEvent == 0) {
303  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {
304  getObjectPtr<TH1F>("ExpEvsCrysSameRing")->Fill(crysID + 0.001, ExpCosmicESame[crysID]);
305  getObjectPtr<TH1F>("ElecCalibvsCrysSameRing")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
306  getObjectPtr<TH1F>("InitialCalibvsCrysSameRing")->Fill(crysID + 0.001, CosmicECalib[crysID]);
307  getObjectPtr<TH1F>("CalibEntriesvsCrysSameRing")->Fill(crysID + 0.001);
308 
309  getObjectPtr<TH1F>("ExpEvsCrysDifferentRing")->Fill(crysID + 0.001, ExpCosmicEDifferent[crysID]);
310  getObjectPtr<TH1F>("ElecCalibvsCrysDifferentRing")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
311  getObjectPtr<TH1F>("InitialCalibvsCrysDifferentRing")->Fill(crysID + 0.001, CosmicECalib[crysID]);
312  getObjectPtr<TH1F>("CalibEntriesvsCrysDifferentRing")->Fill(crysID + 0.001);
313 
314  }
315  }
316 
318  /* Metadata; check if required DB objects have changed */
319  if (iEvent % 10000 == 0) {B2INFO("eclCosmicECollector: iEvent = " << iEvent);}
320  iEvent++;
321 
322  if (m_ECLExpCosmicESame.hasChanged()) {B2FATAL("eclCosmicECollector: ECLExpCosmicESame has changed");}
323  if (m_ECLExpCosmicEDifferent.hasChanged()) {B2FATAL("eclCosmicECollector: ECLExpCosmicEDifferent has changed");}
324  if (m_ElectronicsCalib.hasChanged()) {B2FATAL("eclCosmicECollector: ElectronicsCalib has changed");}
325  if (m_CosmicECalib.hasChanged()) {
326  B2DEBUG(9, "eclCosmicECollector: new values for ECLCosmicECalib");
327  CosmicECalib = m_CosmicECalib->getCalibVector();
328  }
329 
332  memset(&EperCrys[0], 0, EperCrys.size()*sizeof EperCrys[0]);
333  memset(&EnergyPerTC[0], 0, EnergyPerTC.size()*sizeof EnergyPerTC[0]);
334 
335 
336  for (auto& eclDigit : m_eclDigitArray) {
337  int crysID = eclDigit.getCellId() - 1;
338 
340  EperCrys[crysID] = eclDigit.getAmp() * abs(CosmicECalib[crysID]) * ElectronicsCalib[crysID];
341  EnergyPerTC[TCperCrys[crysID]] += EperCrys[crysID];
342  getObjectPtr<TH2F>("RawDigitAmpvsCrys")->Fill(crysID + 0.001, eclDigit.getAmp());
343  }
344  for (int crysID = 0; crysID < ECLElementNumbers::c_NCrystals; crysID++) {HitCrys[crysID] = EperCrys[crysID] > m_minCrysE;}
345 
348  if (m_mockupL1) {
349  float maxTrig = 0.;
350  for (int tc = 0; tc < 576; tc++) {
351  if (EnergyPerTC[tc] > maxTrig) {maxTrig = EnergyPerTC[tc];}
352  }
353  bool ECLtrigger = maxTrig > m_trigThreshold;
354  if (!ECLtrigger) {return;}
355  }
356 
359  for (int i = 0; i < FirstSet[ECLElementNumbers::c_NCrystals]; i++) {
360  if (HitCrys[NeighbourA[i]] && HitCrys[NeighbourB[i]]) {
361  int crysID = CenterCrys[i];
362  if (i == FirstSet[crysID]) {
363 
365  getObjectPtr<TH2F>("EnvsCrysSameRing")->Fill(crysID + 0.001, EperCrys[crysID] / abs(ExpCosmicESame[crysID]));
366  getObjectPtr<TH1F>("ExpEvsCrysSameRing")->Fill(crysID + 0.001, ExpCosmicESame[crysID]);
367  getObjectPtr<TH1F>("ElecCalibvsCrysSameRing")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
368  getObjectPtr<TH1F>("InitialCalibvsCrysSameRing")->Fill(crysID + 0.001, CosmicECalib[crysID]);
369  getObjectPtr<TH1F>("CalibEntriesvsCrysSameRing")->Fill(crysID + 0.001);
370  } else {
371  getObjectPtr<TH2F>("EnvsCrysDifferentRing")->Fill(crysID + 0.001, EperCrys[crysID] / abs(ExpCosmicEDifferent[crysID]));
372  getObjectPtr<TH1F>("ExpEvsCrysDifferentRing")->Fill(crysID + 0.001, ExpCosmicEDifferent[crysID]);
373  getObjectPtr<TH1F>("ElecCalibvsCrysDifferentRing")->Fill(crysID + 0.001, ElectronicsCalib[crysID]);
374  getObjectPtr<TH1F>("InitialCalibvsCrysDifferentRing")->Fill(crysID + 0.001, CosmicECalib[crysID]);
375  getObjectPtr<TH1F>("CalibEntriesvsCrysDifferentRing")->Fill(crysID + 0.001);
376  }
377  }
378  }
379 }
Calibration collector module base class.
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
A class of TC Mapping.
Definition: TrgEclMapping.h:26
int getTCIdFromXtalId(int)
get [TC ID] from [Xtal ID]
DBObjPtr< ECLCrystalCalib > m_ECLExpCosmicEDifferent
Expected energies from database; neighbours in different ThetaID rings.
DBObjPtr< ECLCrystalCalib > m_CosmicECalib
Existing single crystal calibration from DB; will be updated by CAF.
std::vector< float > CosmicECalib
vector obtained from DB object
std::vector< int > FirstSet
First set of 3 crystals for each crystalID.
StoreArray< ECLDigit > m_eclDigitArray
Required input array of eclDigits.
std::vector< float > EnergyPerTC
Energy (GeV) per trigger cell.
std::vector< float > EperCrys
Energy related.
StoreObjPtr< EventMetaData > m_evtMetaData
Store array: EventMetaData.
std::vector< float > ElectronicsCalib
vector obtained from DB object
bool m_mockupL1
Calculate energy per trigger cell in lieu of trigger simulation (false)
std::vector< float > ExpCosmicEDifferent
vector obtained from DB object
std::vector< bool > HitCrys
true if energy>m_minCrysE
DBObjPtr< ECLCrystalCalib > m_ECLExpCosmicESame
Expected energies from database; neighbours in the same ThetaID ring.
std::vector< short int > NeighbourA
if this crystal is > threshold
DBObjPtr< ECLCrystalCalib > m_ElectronicsCalib
Electronics calibration from database.
std::vector< short int > NeighbourB
and this crystal is > threshold
std::vector< float > ExpCosmicESame
vector obtained from DB object
double m_trigThreshold
Minimum energy in trigger cell, if required (0.1 GeV)
double m_minCrysE
Parameters to control the job.
std::vector< short int > TCperCrys
Trigger.
std::vector< short int > CenterCrys
Sets of three crystals that define a useful cosmic.
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
const int c_NCrystals
Number of crystals.
Abstract base class for different kinds of events.