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) :
69 m_DigitizationInitialTime(digitizationInitialTime),
71 m_FPGAStat(c_ScintillatorFirmwareNoSignal),
81 double time, attenuationTime;
111 time = samplingTime * i;
113 exp(-digPar->getPEAttenuationFrequency() * time) * attenuationTime /
129 free(m_amplitudeDirect);
130 free(m_amplitudeReflected);
132 free(m_ADCAmplitude);
133 free(m_SignalTimeDependence);
134 free(m_SignalTimeDependenceDiff);
135 free(m_Photoelectrons);
136 free(m_PhotoelectronIndex);
137 free(m_PhotoelectronIndex2);
154 for (
int i = 0; i < m_DigPar->getNDigitizations(); i++) {
156 m_amplitudeDirect[i] = 0;
157 m_amplitudeReflected[i] = 0;
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) {
192 m_Energy = m_Energy + hit->getEnergyDeposit();
194 double nPhotons = hit->getEnergyDeposit() * m_DigPar->getNPEperMeV();
196 double sipmDistance, time;
198 sipmDistance = hit->getPropagationTime() *
199 m_DigPar->getFiberLightSpeed();
200 time = hit->getTime() + hit->getPropagationTime();
202 m_MCTime = hit->getTime();
205 if (hit->getTime() < m_MCTime)
206 m_MCTime = hit->getTime();
207 if (time < m_SiPMMCTime)
211 sipmDistance = 0.5 * stripLength - hit->getLocalPosition().X();
212 time = hit->getTime() + sipmDistance / m_DigPar->getFiberLightSpeed();
216 m_MCTime = time < m_MCTime ? time : m_MCTime;
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);
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];
238 fillSiPMOutput(m_amplitude,
true,
true);
240 if (m_DigPar->getMeanSiPMNoise() > 0)
241 addRandomSiPMNoise();
243 m_FPGAStat = m_fitter->fit(m_ADCAmplitude, m_Threshold, &m_FPGAFit);
244 if (m_FPGAStat != c_ScintillatorFirmwareSuccessfulFit)
255 for (i = 0; i < m_DigPar->getNDigitizations(); i++)
256 m_amplitude[i] = m_amplitude[i] +
257 gRandom->Poisson(m_DigPar->getMeanSiPMNoise());
262 int* currentIndexArray, *newIndexArray, *tmpIndexArray;
263 int i, i1, i2, i1Max, i2Max, j, mergeSize;
264 currentIndexArray = m_PhotoelectronIndex;
265 newIndexArray = m_PhotoelectronIndex2;
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) {
281 if (m_Photoelectrons[currentIndexArray[i1]].bin <
282 m_Photoelectrons[currentIndexArray[i2]].bin) {
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() *
313 m_Time->getTDCPeriod();
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++) {
323 if (m_npe >= m_PhotoelectronBufferSize)
324 reallocPhotoElectronBuffers(m_npe + 100);
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 +
344 timeShift - m_DigitizationInitialTime;
345 if (hitTime >= maxHitTime)
348 m_Photoelectrons[m_npe].bin = floor(hitTime / samplingTime);
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;
423 double attenuationTime, sig, expSum;
425 int ind1, ind2, ind3;
429 attenuationTime = 1.0 / m_DigPar->getPEAttenuationFrequency();
430 indexArray = sortPhotoelectrons(m_npe);
435 bin = m_Photoelectrons[indexArray[ind1]].bin;
440 if (bin != m_Photoelectrons[indexArray[ind2]].bin)
444 for (ind3 = ind1; ind3 != ind2; ind3++) {
445 if (m_Photoelectrons[indexArray[ind3]].isReflected && !useReflected)
447 if (!m_Photoelectrons[indexArray[ind3]].isReflected && !useDirect)
450 sig = attenuationTime - m_Photoelectrons[indexArray[ind3]].expTime *
451 m_SignalTimeDependence[bin + 1];
452 hist[bin] = hist[bin] + sig;
454 expSum = expSum + m_Photoelectrons[indexArray[ind3]].expTime;
457 maxBin = m_DigPar->getNDigitizations() - 1;
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;
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);
498 intg = m_FPGAFit.getAmplitude();
499 return intg * m_DigPar->getPEAttenuationFrequency() /
500 m_PhotoelectronAmplitude;
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(),
526 m_DigPar->getNDigitizations(), 0, m_histRange);
527 histAmplitudeReflected =
528 new TH1D(
"histAmplitudeReflected", m_stripName.c_str(),
529 m_DigPar->getNDigitizations(), 0, m_histRange);
531 new TH1D(
"histAmplitude", m_stripName.c_str(),
532 m_DigPar->getNDigitizations(), 0, m_histRange);
534 new TH1D(
"histADCAmplitude", m_stripName.c_str(),
535 m_DigPar->getNDigitizations(), 0, m_histRange);
536 }
catch (std::bad_alloc& ba) {
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]);
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.
float getADCPedestal() const
Get ADC pedestal.
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.
FPGA fit simulation data.
float getEnergyDeposit() const
Get energy deposit.
double getTDCPeriod() const
Get TDC period.
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.
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.
double getNPhotoelectrons()
Get number of photoelectrons (fit result).
struct Photoelectron * m_Photoelectrons
Buffer for photoelectron data.
KLMScintillatorFirmwareFitResult * getFPGAFit()
Get fit data.
int * m_ADCAmplitude
Digital amplitude.
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_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.