10#include <klm/simulation/ScintillatorSimulator.h>
13#include <klm/bklm/geometry/GeometryPar.h>
14#include <klm/eklm/geometry/GeometryData.h>
15#include <klm/dataobjects/KLMElementNumbers.h>
18#include <framework/dataobjects/EventMetaData.h>
19#include <framework/datastore/StoreObjPtr.h>
20#include <framework/gearbox/Unit.h>
21#include <framework/logging/Logger.h>
34static const char MemErr[] =
"Memory allocation error.";
65 double digitizationInitialTime,
bool debug) :
78 const double samplingTime =
m_DigPar->getADCSamplingTDCPeriods() *
81 double time, attenuationTime;
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 /
154 for (
int i = 0; i <
m_DigPar->getNDigitizations(); i++) {
164 const std::multimap<KLMChannelNumber, const KLMSimHit*>::iterator& firstHit,
165 const std::multimap<KLMChannelNumber, const KLMSimHit*>::iterator& end)
167 m_stripName =
"strip_" + std::to_string(firstHit->first);
175 geoPar->
findModule(hit->getSection(), hit->getSector(), hit->getLayer());
177 2.0 * (hit->isPhiReadout() ?
178 module->getPhiScintHalfLength(hit->getStrip()) :
179 module->getZScintHalfLength(hit->getStrip()));
182 hit->getStrip()) / CLHEP::mm *
Unit::mm;
184 std::vector<const KLMSimHit*> hits;
185 for (std::multimap<KLMChannelNumber, const KLMSimHit*>::iterator it = firstHit;
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) {
194 double nPhotons = hit->getEnergyDeposit() *
m_DigPar->getNPEperMeV();
196 double sipmDistance, time;
198 sipmDistance = hit->getPropagationTime() *
200 time = hit->getTime() + hit->getPropagationTime();
211 sipmDistance = 0.5 * stripLength - hit->getLocalPosition().X();
212 time = hit->getTime() + sipmDistance /
m_DigPar->getFiberLightSpeed();
218 int generatedPhotons = gRandom->Poisson(nPhotons);
220 hit->getTime(),
false);
221 if (
m_DigPar->getMirrorReflectiveIndex() > 0) {
222 generatedPhotons = gRandom->Poisson(nPhotons);
224 hit->getTime(),
true);
235 for (
int i = 0; i <
m_DigPar->getNDigitizations(); i++)
240 if (
m_DigPar->getMeanSiPMNoise() > 0)
244 if (
m_FPGAStat != c_ScintillatorFirmwareSuccessfulFit)
255 for (i = 0; i <
m_DigPar->getNDigitizations(); i++)
257 gRandom->PoissonD(
m_DigPar->getMeanSiPMNoise());
262 int* currentIndexArray, *newIndexArray, *tmpIndexArray;
263 int i, i1, i2, i1Max, i2Max, j, mergeSize;
267 while (mergeSize < nPhotoelectrons) {
268 for (i = 0; i < nPhotoelectrons; i = i + 2 * mergeSize) {
272 if (i2 > nPhotoelectrons)
273 i2 = nPhotoelectrons;
275 i2Max = i2 + mergeSize;
276 if (i2Max > nPhotoelectrons)
277 i2Max = nPhotoelectrons;
278 while (i1 < i1Max || i2 < i2Max) {
283 newIndexArray[j] = currentIndexArray[i1];
286 newIndexArray[j] = currentIndexArray[i2];
290 newIndexArray[j] = currentIndexArray[i1];
294 newIndexArray[j] = currentIndexArray[i2];
300 tmpIndexArray = currentIndexArray;
301 currentIndexArray = newIndexArray;
302 newIndexArray = tmpIndexArray;
303 mergeSize = mergeSize * 2;
305 return currentIndexArray;
309 double stripLen,
double distSiPM,
int nPhotons,
double timeShift,
312 const double samplingTime =
m_DigPar->getADCSamplingTDCPeriods() *
314 const double maxHitTime =
m_DigPar->getNDigitizations() * samplingTime;
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();
322 for (i = 0; i < nPhotons; i++) {
325 cosTheta = gRandom->Uniform(
m_DigPar->getMinCosTheta(), 1);
327 hitDist = distSiPM / cosTheta;
329 hitDist = (2.0 * stripLen - distSiPM) / cosTheta;
331 selection = gRandom->Uniform();
332 if (selection > exp(-hitDist * inverseAttenuationLength))
336 selection = gRandom->Uniform();
337 if (selection >
m_DigPar->getMirrorReflectiveIndex())
341 gRandom->Exp(
m_DigPar->getScintillatorDeExcitationTime()) +
342 gRandom->Exp(
m_DigPar->getFiberDeExcitationTime());
343 hitTime = hitDist * inverseLightSpeed + deExcitationTime +
345 if (hitTime >= maxHitTime)
352 exp(
m_DigPar->getPEAttenuationFrequency() * hitTime);
423 double attenuationTime, sig, expSum;
425 int ind1, ind2, ind3;
429 attenuationTime = 1.0 /
m_DigPar->getPEAttenuationFrequency();
444 for (ind3 = ind1; ind3 != ind2; ind3++) {
452 hist[bin] = hist[bin] + sig;
457 maxBin =
m_DigPar->getNDigitizations() - 1;
460 for (i = bin + 1; i <= maxBin; i++) {
462 hist[i] = hist[i] + sig;
476 B2FATAL(
"Incorrect EKLM ADC simulation parameters.");
477 for (i = 0; i <
m_DigPar->getNDigitizations(); i++) {
479 if (amp < m_DigPar->getADCSaturation())
499 return intg *
m_DigPar->getPEAttenuationFrequency() /
518 TFile* hfile =
nullptr;
519 TH1D* histAmplitudeDirect =
nullptr;
520 TH1D* histAmplitudeReflected =
nullptr;
521 TH1D* histAmplitude =
nullptr;
522 TH1D* histADCAmplitude =
nullptr;
524 histAmplitudeDirect =
525 new TH1D(
"histAmplitudeDirect",
m_stripName.c_str(),
527 histAmplitudeReflected =
528 new TH1D(
"histAmplitudeReflected",
m_stripName.c_str(),
536 }
catch (std::bad_alloc& ba) {
539 for (i = 0; i <
m_DigPar->getNDigitizations(); i++) {
542 histAmplitude->SetBinContent(i + 1,
m_amplitude[i]);
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";
549 hfile =
new TFile(str.c_str(),
"NEW");
550 }
catch (std::bad_alloc& ba) {
553 hfile->Append(histAmplitudeDirect);
554 hfile->Append(histAmplitudeReflected);
555 hfile->Append(histAmplitude);
556 hfile->Append(histADCAmplitude);
static const GeometryData & Instance(enum DataSource dataSource=c_Database, const GearDir *gearDir=nullptr)
Instantiation.
double getStripLength(int strip) const
Get strip length.
Class to store KLM scintillator simulation parameters in the database.
int getThreshold() const
Get threshold.
float getPhotoelectronAmplitude() const
Get photoelectron amplitude.
float getPedestal() const
Get pedestal.
FPGA fit simulation data.
float getEnergyDeposit() const
Get energy deposit.
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.
const KLMTime * m_Time
Time.
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.
double m_Energy
Total energy deposited in the strip.
float m_SiPMMCTime
MC time at SiPM.
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),.
~ScintillatorSimulator()
Destructor.
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).
double m_Pedestal
Pedestal.
void reallocPhotoElectronBuffers(int size)
Reallocate photoelectron buffers.
bool m_Debug
Debug mode (generates additional output files with histograms).
double m_DigitizationInitialTime
Initial digitization time.
double getNPhotoelectrons()
Get number of photoelectrons (fit result).
struct Photoelectron * m_Photoelectrons
Buffer for photoelectron data.
ScintillatorFirmware * m_fitter
Fitter.
std::string m_stripName
Name of the strip.
enum ScintillatorFirmwareFitStatus m_FPGAStat
FPGA fit status.
KLMScintillatorFirmwareFitResult * getFPGAFit()
Get fit data.
int * m_ADCAmplitude
Digital amplitude.
KLMScintillatorFirmwareFitResult m_FPGAFit
FPGA 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.
float * m_amplitude
Analog amplitude.
void fillSiPMOutput(float *hist, bool useDirect, bool useReflected)
Fill SiPM output.
int m_Threshold
Threshold.
int * sortPhotoelectrons(int nPhotoelectrons)
Sort photoelectrons.
int m_npe
Number of photoelectrons (generated).
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.
static const double mm
[millimeters]
Provides BKLM geometry parameters for simulation, reconstruction etc (from Gearbox or DataBase)
const Module * findModule(int section, int sector, int layer) const
Get the pointer to the definition of a module.
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Abstract base class for different kinds of events.