Belle II Software development
ScintillatorSimulator.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 <klm/simulation/ScintillatorSimulator.h>
11
12/* KLM headers. */
13#include <klm/bklm/geometry/GeometryPar.h>
14#include <klm/eklm/geometry/GeometryData.h>
15#include <klm/dataobjects/KLMElementNumbers.h>
16
17/* Basf2 headers. */
18#include <framework/dataobjects/EventMetaData.h>
19#include <framework/datastore/StoreObjPtr.h>
20#include <framework/gearbox/Unit.h>
21#include <framework/logging/Logger.h>
22
23/* ROOT headers. */
24#include <TFile.h>
25#include <TH1D.h>
26#include <TRandom.h>
27
28/* C++ headers. */
29#include <algorithm>
30#include <string>
31
32using namespace Belle2;
33
34static const char MemErr[] = "Memory allocation error.";
35
36static bool compareKLMSimHits(const KLMSimHit* hit1, const KLMSimHit* hit2)
37{
38 return hit1->getEnergyDeposit() < hit2->getEnergyDeposit();
39}
40
42{
44 /*
45 * Here there is a memory leak in case of realloc() failure, but it does not
46 * matter because a fatal error is issued in this case.
47 */
49 (struct Photoelectron*)realloc(m_Photoelectrons,
50 size * sizeof(struct Photoelectron));
52 size * sizeof(int));
54 size * sizeof(int));
55 if (size != 0) {
56 if (m_Photoelectrons == nullptr || m_PhotoelectronIndex == nullptr ||
57 m_PhotoelectronIndex2 == nullptr)
58 B2FATAL(MemErr);
59 }
60}
61
65 double digitizationInitialTime, bool debug) :
66 m_Time(&(KLMTime::Instance())),
67 m_DigPar(digPar),
68 m_fitter(fitter),
69 m_DigitizationInitialTime(digitizationInitialTime),
70 m_Debug(debug),
71 m_FPGAStat(c_ScintillatorFirmwareNoSignal),
72 m_npe(0),
73 m_Energy(0),
74 m_MCTime(-1),
75 m_SiPMMCTime(-1)
76{
77 int i;
78 const double samplingTime = m_DigPar->getADCSamplingTDCPeriods() *
80 /* cppcheck-suppress variableScope */
81 double time, attenuationTime;
82 m_histRange = m_DigPar->getNDigitizations() * samplingTime;
86 /* Amplitude arrays. */
87 m_amplitudeDirect = (float*)malloc(m_DigPar->getNDigitizations() *
88 sizeof(float));
89 if (m_amplitudeDirect == nullptr)
90 B2FATAL(MemErr);
92 sizeof(float));
93 if (m_amplitudeReflected == nullptr)
94 B2FATAL(MemErr);
95 m_amplitude = (float*)malloc(m_DigPar->getNDigitizations() * sizeof(float));
96 if (m_amplitude == nullptr)
97 B2FATAL(MemErr);
98 m_ADCAmplitude = (int*)malloc(m_DigPar->getNDigitizations() * sizeof(int));
99 if (m_ADCAmplitude == nullptr)
100 B2FATAL(MemErr);
101 m_SignalTimeDependence = (double*)malloc((m_DigPar->getNDigitizations() + 1) *
102 sizeof(double));
103 if (m_SignalTimeDependence == nullptr)
104 B2FATAL(MemErr);
106 sizeof(double));
107 if (m_SignalTimeDependenceDiff == nullptr)
108 B2FATAL(MemErr);
109 attenuationTime = 1.0 / m_DigPar->getPEAttenuationFrequency();
110 for (i = 0; i <= m_DigPar->getNDigitizations(); i++) {
111 time = samplingTime * i;
113 exp(-digPar->getPEAttenuationFrequency() * time) * attenuationTime /
114 samplingTime;
115 if (i > 0) {
118 }
119 }
120 m_Photoelectrons = nullptr;
121 m_PhotoelectronIndex = nullptr;
122 m_PhotoelectronIndex2 = nullptr;
124}
125
126
128{
129 free(m_amplitudeDirect);
130 free(m_amplitudeReflected);
131 free(m_amplitude);
132 free(m_ADCAmplitude);
133 free(m_SignalTimeDependence);
134 free(m_SignalTimeDependenceDiff);
135 free(m_Photoelectrons);
136 free(m_PhotoelectronIndex);
137 free(m_PhotoelectronIndex2);
138}
139
141 const KLMScintillatorFEEData* FEEData)
142{
143 m_Pedestal = FEEData->getPedestal();
144 m_PhotoelectronAmplitude = FEEData->getPhotoelectronAmplitude();
145 m_Threshold = FEEData->getThreshold();
146}
147
149{
150 m_MCTime = -1;
151 m_SiPMMCTime = -1;
152 m_npe = 0;
153 m_Energy = 0;
154 for (int i = 0; i < m_DigPar->getNDigitizations(); i++) {
155 if (m_Debug) {
156 m_amplitudeDirect[i] = 0;
157 m_amplitudeReflected[i] = 0;
158 } else
159 m_amplitude[i] = 0;
160 }
161}
162
164 const std::multimap<KLMChannelNumber, const KLMSimHit*>::iterator& firstHit,
165 const std::multimap<KLMChannelNumber, const KLMSimHit*>::iterator& end)
166{
167 m_stripName = "strip_" + std::to_string(firstHit->first);
168 prepareSimulation();
170 const KLMSimHit* hit = firstHit->second;
171 double stripLength;
172 bool isBKLM = (hit->getSubdetector() == KLMElementNumbers::c_BKLM);
173 if (isBKLM) {
174 const bklm::Module* module =
175 geoPar->findModule(hit->getSection(), hit->getSector(), hit->getLayer());
176 stripLength =
177 2.0 * (hit->isPhiReadout() ?
178 module->getPhiScintHalfLength(hit->getStrip()) :
179 module->getZScintHalfLength(hit->getStrip()));
180 } else {
182 hit->getStrip()) / CLHEP::mm * Unit::mm;
183 }
184 std::vector<const KLMSimHit*> hits;
185 for (std::multimap<KLMChannelNumber, const KLMSimHit*>::iterator it = firstHit;
186 it != end; ++it)
187 hits.push_back(it->second);
188 std::sort(hits.begin(), hits.end(), compareKLMSimHits);
189 for (std::vector<const KLMSimHit*>::iterator it = hits.begin();
190 it != hits.end(); ++it) {
191 hit = *it;
192 m_Energy = m_Energy + hit->getEnergyDeposit();
193 /* Poisson mean for number of photons. */
194 double nPhotons = hit->getEnergyDeposit() * m_DigPar->getNPEperMeV();
195 /* Fill histograms. */
196 double sipmDistance, time;
197 if (isBKLM) {
198 sipmDistance = hit->getPropagationTime() *
199 m_DigPar->getFiberLightSpeed();
200 time = hit->getTime() + hit->getPropagationTime();
201 if (m_MCTime < 0) {
202 m_MCTime = hit->getTime();
203 m_SiPMMCTime = time;
204 } else {
205 if (hit->getTime() < m_MCTime)
206 m_MCTime = hit->getTime();
207 if (time < m_SiPMMCTime)
208 m_SiPMMCTime = time;
209 }
210 } else {
211 sipmDistance = 0.5 * stripLength - hit->getLocalPosition().X();
212 time = hit->getTime() + sipmDistance / m_DigPar->getFiberLightSpeed();
213 if (m_MCTime < 0)
214 m_MCTime = time;
215 else
216 m_MCTime = time < m_MCTime ? time : m_MCTime;
217 }
218 int generatedPhotons = gRandom->Poisson(nPhotons);
219 generatePhotoelectrons(stripLength, sipmDistance, generatedPhotons,
220 hit->getTime(), false);
221 if (m_DigPar->getMirrorReflectiveIndex() > 0) {
222 generatedPhotons = gRandom->Poisson(nPhotons);
223 generatePhotoelectrons(stripLength, sipmDistance, generatedPhotons,
224 hit->getTime(), true);
225 }
226 }
227 performSimulation();
228}
229
231{
232 if (m_Debug) {
233 fillSiPMOutput(m_amplitudeDirect, true, false);
234 fillSiPMOutput(m_amplitudeReflected, false, true);
235 for (int i = 0; i < m_DigPar->getNDigitizations(); i++)
236 m_amplitude[i] = m_amplitudeDirect[i] + m_amplitudeReflected[i];
237 } else
238 fillSiPMOutput(m_amplitude, true, true);
239 /* SiPM noise and ADC. */
240 if (m_DigPar->getMeanSiPMNoise() > 0)
241 addRandomSiPMNoise();
242 simulateADC();
243 m_FPGAStat = m_fitter->fit(m_ADCAmplitude, m_Threshold, &m_FPGAFit);
244 if (m_FPGAStat != c_ScintillatorFirmwareSuccessfulFit)
245 return;
246 if (m_Debug) {
247 if (m_npe >= 10)
248 debugOutput();
249 }
250}
251
253{
254 int i;
255 for (i = 0; i < m_DigPar->getNDigitizations(); i++)
256 m_amplitude[i] = m_amplitude[i] +
257 gRandom->Poisson(m_DigPar->getMeanSiPMNoise());
258}
259
261{
262 int* currentIndexArray, *newIndexArray, *tmpIndexArray;
263 int i, i1, i2, i1Max, i2Max, j, mergeSize;
264 currentIndexArray = m_PhotoelectronIndex;
265 newIndexArray = m_PhotoelectronIndex2;
266 mergeSize = 1;
267 while (mergeSize < nPhotoelectrons) {
268 for (i = 0; i < nPhotoelectrons; i = i + 2 * mergeSize) {
269 i1 = i;
270 j = i;
271 i2 = i + mergeSize;
272 if (i2 > nPhotoelectrons)
273 i2 = nPhotoelectrons;
274 i1Max = i2;
275 i2Max = i2 + mergeSize;
276 if (i2Max > nPhotoelectrons)
277 i2Max = nPhotoelectrons;
278 while (i1 < i1Max || i2 < i2Max) {
279 if (i1 < i1Max) {
280 if (i2 < i2Max) {
281 if (m_Photoelectrons[currentIndexArray[i1]].bin <
282 m_Photoelectrons[currentIndexArray[i2]].bin) {
283 newIndexArray[j] = currentIndexArray[i1];
284 i1++;
285 } else {
286 newIndexArray[j] = currentIndexArray[i2];
287 i2++;
288 }
289 } else {
290 newIndexArray[j] = currentIndexArray[i1];
291 i1++;
292 }
293 } else {
294 newIndexArray[j] = currentIndexArray[i2];
295 i2++;
296 }
297 j++;
298 }
299 }
300 tmpIndexArray = currentIndexArray;
301 currentIndexArray = newIndexArray;
302 newIndexArray = tmpIndexArray;
303 mergeSize = mergeSize * 2;
304 }
305 return currentIndexArray;
306}
307
309 double stripLen, double distSiPM, int nPhotons, double timeShift,
310 bool isReflected)
311{
312 const double samplingTime = m_DigPar->getADCSamplingTDCPeriods() *
313 m_Time->getTDCPeriod();
314 const double maxHitTime = m_DigPar->getNDigitizations() * samplingTime;
315 int i;
316 /* cppcheck-suppress variableScope */
317 double hitTime, deExcitationTime, cosTheta, hitDist, selection;
318 double inverseLightSpeed, inverseAttenuationLength;
319 inverseLightSpeed = 1.0 / m_DigPar->getFiberLightSpeed();
320 inverseAttenuationLength = 1.0 / m_DigPar->getAttenuationLength();
321 /* Generation of photoelectrons. */
322 for (i = 0; i < nPhotons; i++) {
323 if (m_npe >= m_PhotoelectronBufferSize)
324 reallocPhotoElectronBuffers(m_npe + 100);
325 cosTheta = gRandom->Uniform(m_DigPar->getMinCosTheta(), 1);
326 if (!isReflected)
327 hitDist = distSiPM / cosTheta;
328 else
329 hitDist = (2.0 * stripLen - distSiPM) / cosTheta;
330 /* Fiber absorption. */
331 selection = gRandom->Uniform();
332 if (selection > exp(-hitDist * inverseAttenuationLength))
333 continue;
334 /* Account for mirror reflective index. */
335 if (isReflected) {
336 selection = gRandom->Uniform();
337 if (selection > m_DigPar->getMirrorReflectiveIndex())
338 continue;
339 }
340 deExcitationTime =
341 gRandom->Exp(m_DigPar->getScintillatorDeExcitationTime()) +
342 gRandom->Exp(m_DigPar->getFiberDeExcitationTime());
343 hitTime = hitDist * inverseLightSpeed + deExcitationTime +
344 timeShift - m_DigitizationInitialTime;
345 if (hitTime >= maxHitTime)
346 continue;
347 if (hitTime >= 0)
348 m_Photoelectrons[m_npe].bin = floor(hitTime / samplingTime);
349 else
350 m_Photoelectrons[m_npe].bin = -1;
351 m_Photoelectrons[m_npe].expTime =
352 exp(m_DigPar->getPEAttenuationFrequency() * hitTime);
353 m_Photoelectrons[m_npe].isReflected = isReflected;
354 m_PhotoelectronIndex[m_npe] = m_npe;
355 m_npe++;
356 }
357}
358
359/*
360 * ADC signal corresponding to a photoelectron is
361 *
362 * exp(-(t - tau) / t0),
363 *
364 * where tau is the hit time and t0 = 1.0 / m_DigPar->PEAttenuationFreq. Its
365 * integral from t1 to t2 is
366 *
367 * t0 * exp(-(t1 - tau) / t0) - t0 * exp(-(t2 - tau) / t0).
368 *
369 * The integration is performed over digitization bins from (t_dig * i) to
370 * (t_dig * (i + 1)), where t_dig = m_DigPar->ADCSamplingTDCPeriods() *
371 * m_Time->getTDCPeriod() and i is the bin number.
372 * The integrals are
373 *
374 * I1 = t0 - t0 * exp(-(t_dig * (i + 1) - tau) / t0)
375 *
376 * for the first signal bin (t_dig * i <= tau < t_dig * (i + 1)) and
377 *
378 * I2 = t0 * exp(-(t_dig * i - tau) / t0) -
379 * t0 * exp(-(t_dig * (i + 1) - tau) / t0)
380 *
381 * for the following bins. The integrals contain expressions that do not depend
382 * on the hit time and may be calculated preliminary:
383 *
384 * B1 = t0 * exp(-(t_dig * (i + 1) / t0)
385 *
386 * and
387 *
388 * B2 = t0 * exp(-(t_dig * i) / t0) - t0 * exp(-(t_dig * (i + 1)) / t0).
389 *
390 * In terms of B1 and B2 the integrals are equal to
391 *
392 * I1 = t0 - B1 * exp(tau / t0)
393 *
394 * and
395 *
396 * I2 = B2 * exp(tau / t0).
397 *
398 * The sum of integrals for all photoelectrons is
399 *
400 * I = \sum_{hits before this bin} B2 * exp(tau_j / t0) +
401 * \sum_{hits in this bin} t0 - B1 * exp(tau_j / t0),
402 *
403 * where tau_j is the time of j-th hit. The bin-dependent expressions B1 and B2
404 * are the same for all hits:
405 *
406 * I = B2 * \sum_{hits before this bin} exp(tau_j / t0) +
407 * N_i * t0 - B1 * \sum_{hits in this bin} exp(tau_j / t0).
408 *
409 * where N_i is the number of hits in this (i-th) bin.
410 *
411 * In order to get the approximation of the function value, the integrals
412 * over bins are normalized:
413 *
414 * I -> I / t_dig.
415 *
416 * The normalization (1 / t_dig) is included into the definitions of B1 and B2.
417 */
418void KLM::ScintillatorSimulator::fillSiPMOutput(float* hist, bool useDirect,
419 bool useReflected)
420{
421 /* cppcheck-suppress variableScope */
422 int i, bin, maxBin;
423 double attenuationTime, sig, expSum;
424 /* cppcheck-suppress variableScope */
425 int ind1, ind2, ind3;
426 int* indexArray;
427 if (m_npe == 0)
428 return;
429 attenuationTime = 1.0 / m_DigPar->getPEAttenuationFrequency();
430 indexArray = sortPhotoelectrons(m_npe);
431 ind1 = 0;
432 expSum = 0;
433 while (1) {
434 ind2 = ind1;
435 bin = m_Photoelectrons[indexArray[ind1]].bin;
436 while (1) {
437 ind2++;
438 if (ind2 == m_npe)
439 break;
440 if (bin != m_Photoelectrons[indexArray[ind2]].bin)
441 break;
442 }
443 /* Now ind1 .. ind2 - photoelectrons in current bin. */
444 for (ind3 = ind1; ind3 != ind2; ind3++) {
445 if (m_Photoelectrons[indexArray[ind3]].isReflected && !useReflected)
446 continue;
447 if (!m_Photoelectrons[indexArray[ind3]].isReflected && !useDirect)
448 continue;
449 if (bin >= 0) {
450 sig = attenuationTime - m_Photoelectrons[indexArray[ind3]].expTime *
451 m_SignalTimeDependence[bin + 1];
452 hist[bin] = hist[bin] + sig;
453 }
454 expSum = expSum + m_Photoelectrons[indexArray[ind3]].expTime;
455 }
456 if (ind2 == m_npe)
457 maxBin = m_DigPar->getNDigitizations() - 1;
458 else
459 maxBin = m_Photoelectrons[indexArray[ind2]].bin;
460 for (i = bin + 1; i <= maxBin; i++) {
461 sig = m_SignalTimeDependenceDiff[i] * expSum;
462 hist[i] = hist[i] + sig;
463 }
464 if (ind2 == m_npe)
465 break;
466 ind1 = ind2;
467 }
468}
469
471{
472 int i;
473 /* cppcheck-suppress variableScope */
474 double amp;
475 if (m_Pedestal == 0 || m_PhotoelectronAmplitude == 0)
476 B2FATAL("Incorrect EKLM ADC simulation parameters.");
477 for (i = 0; i < m_DigPar->getNDigitizations(); i++) {
478 amp = m_Pedestal - m_PhotoelectronAmplitude * m_amplitude[i];
479 if (amp < m_DigPar->getADCSaturation())
480 amp = m_DigPar->getADCSaturation();
481 m_ADCAmplitude[i] = floor(amp);
482 }
483}
484
486{
487 return &m_FPGAFit;
488}
489
490enum KLM::ScintillatorFirmwareFitStatus KLM::ScintillatorSimulator::getFitStatus() const
491{
492 return m_FPGAStat;
493}
494
496{
497 double intg;
498 intg = m_FPGAFit.getAmplitude();
499 return intg * m_DigPar->getPEAttenuationFrequency() /
500 m_PhotoelectronAmplitude;
501}
502
504{
505 return m_npe;
506}
507
509{
510 return m_Energy;
511}
512
514{
515 int i;
516 std::string str;
518 TFile* hfile = nullptr;
519 TH1D* histAmplitudeDirect = nullptr;
520 TH1D* histAmplitudeReflected = nullptr;
521 TH1D* histAmplitude = nullptr;
522 TH1D* histADCAmplitude = nullptr;
523 try {
524 histAmplitudeDirect =
525 new TH1D("histAmplitudeDirect", m_stripName.c_str(),
526 m_DigPar->getNDigitizations(), 0, m_histRange);
527 histAmplitudeReflected =
528 new TH1D("histAmplitudeReflected", m_stripName.c_str(),
529 m_DigPar->getNDigitizations(), 0, m_histRange);
530 histAmplitude =
531 new TH1D("histAmplitude", m_stripName.c_str(),
532 m_DigPar->getNDigitizations(), 0, m_histRange);
533 histADCAmplitude =
534 new TH1D("histADCAmplitude", m_stripName.c_str(),
535 m_DigPar->getNDigitizations(), 0, m_histRange);
536 } catch (std::bad_alloc& ba) {
537 B2FATAL(MemErr);
538 }
539 for (i = 0; i < m_DigPar->getNDigitizations(); i++) {
540 histAmplitudeDirect->SetBinContent(i + 1, m_amplitudeDirect[i]);
541 histAmplitudeReflected->SetBinContent(i + 1, m_amplitudeReflected[i]);
542 histAmplitude->SetBinContent(i + 1, m_amplitude[i]);
543 histADCAmplitude->SetBinContent(i + 1, m_ADCAmplitude[i]);
544 }
545 str = std::string("experiment_") + std::to_string(event->getExperiment()) +
546 "_run_" + std::to_string(event->getRun()) + "_event_" +
547 std::to_string(event->getEvent()) + "_" + m_stripName + ".root";
548 try {
549 hfile = new TFile(str.c_str(), "NEW");
550 } catch (std::bad_alloc& ba) {
551 B2FATAL(MemErr);
552 }
553 hfile->Append(histAmplitudeDirect);
554 hfile->Append(histAmplitudeReflected);
555 hfile->Append(histAmplitude);
556 hfile->Append(histADCAmplitude);
557 hfile->Write();
558 hfile->Close();
559}
560
static const GeometryData & Instance(enum DataSource dataSource=c_Database, const GearDir *gearDir=nullptr)
Instantiation.
Definition: GeometryData.cc:33
double getStripLength(int strip) const
Get strip length.
Definition: GeometryData.h:71
Class to store KLM scintillator simulation parameters in the database.
float getPEAttenuationFrequency() const
Get attenuation frequency of a single photoelectron pulse.
int getADCThreshold() const
Get ADC readout corresponding to saturation.
float getADCPEAmplitude() const
Get ADC photoelectron amplitude.
int getADCSamplingTDCPeriods() const
Get ADC sampling time in TDC periods.
int getNDigitizations() const
Get number of digitizations (points) in one sample.
int getThreshold() const
Get threshold.
float getPhotoelectronAmplitude() const
Get photoelectron amplitude.
float getPedestal() const
Get pedestal.
KLM simulation hit.
Definition: KLMSimHit.h:31
float getEnergyDeposit() const
Get energy deposit.
Definition: KLMSimHit.h:260
KLM time conversion.
Definition: KLMTime.h:27
double getTDCPeriod() const
Get TDC period.
Definition: KLMTime.h:45
void setFEEData(const KLMScintillatorFEEData *FEEData)
Set FEE data.
int * m_PhotoelectronIndex2
Buffer for photoelectron indices.
float * m_amplitudeReflected
Analog amplitude (reflected).
void debugOutput()
Debug output (signal and fit result histograms).
enum ScintillatorFirmwareFitStatus getFitStatus() const
Get fit status.
double * m_SignalTimeDependence
Buffer for signal time dependence calculation.
void generatePhotoelectrons(double stripLen, double distSiPM, int nPhotons, double timeShift, bool isReflected)
Generate photoelectrons.
double * m_SignalTimeDependenceDiff
Buffer for signal time dependence calculation.
float * m_amplitudeDirect
Analog amplitude (direct).
void addRandomSiPMNoise()
Add random noise to the signal (amplitude-dependend).
void simulateADC()
Simulate ADC (create digital signal from analog),.
void prepareSimulation()
Prepare simulation.
double getEnergy()
Get total energy deposited in the strip (sum over ssimulation hits).
double m_histRange
Time range, (number of digitizations) * (ADC sampling time).
void reallocPhotoElectronBuffers(int size)
Reallocate photoelectron buffers.
double getNPhotoelectrons()
Get number of photoelectrons (fit result).
struct Photoelectron * m_Photoelectrons
Buffer for photoelectron data.
KLMScintillatorFirmwareFitResult * getFPGAFit()
Get fit data.
void performSimulation()
Perform common simulation stage.
double m_PhotoelectronAmplitude
Photoelectron amplitude.
int getNGeneratedPhotoelectrons()
Get generated number of photoelectrons.
int * m_PhotoelectronIndex
Buffer for photoelectron indices.
void simulate(const std::multimap< KLMChannelNumber, const KLMSimHit * >::iterator &firstHit, const std::multimap< KLMChannelNumber, const KLMSimHit * >::iterator &end)
Simulate a strip.
void fillSiPMOutput(float *hist, bool useDirect, bool useReflected)
Fill SiPM output.
int * sortPhotoelectrons(int nPhotoelectrons)
Sort photoelectrons.
int m_PhotoelectronBufferSize
Size of photoelectron data buffer.
ScintillatorSimulator(const KLMScintillatorDigitizationParameters *digPar, ScintillatorFirmware *fitter, double digitizationInitialTime, bool debug)
Constructor.
const KLMScintillatorDigitizationParameters * m_DigPar
Parameters.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
static const double mm
[millimeters]
Definition: Unit.h:70
Provides BKLM geometry parameters for simulation, reconstruction etc (from Gearbox or DataBase)
Definition: GeometryPar.h:37
const Module * findModule(int section, int sector, int layer) const
Get the pointer to the definition of a module.
Definition: GeometryPar.cc:721
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Definition: GeometryPar.cc:27
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Definition: Module.h:76
Abstract base class for different kinds of events.