Belle II Software development
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
26using namespace std;
27using namespace Belle2;
28using namespace ECL;
29
30
32// Register the Module
34REG_MODULE(eclCosmicECollector);
35
37// Implementation
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.
STL namespace.