ATLAS Offline Software
Loading...
Searching...
No Matches
TileDigitsFromPulse.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5//*****************************************************************************
6// Filename : TileDigitsFromPulse.cxx
7// Author : Simon Molander
8// Created : February 2013
9//
10// DESCRIPTION
11//
12// Create TileDigits from simulated pulses.
13//
14// HISTORY:
15//
16// BUGS:
17//
18//*****************************************************************************
19
20// Tile includes
28
29//Simulator includes
33
34// Athena includes
37//Random number service
40
41#include <CLHEP/Random/Randomize.h>
42#include <CLHEP/Units/SystemOfUnits.h>
43
44//Root includes
45#include "TRandom3.h"
46#include "TFile.h"
47#include "TH1F.h"
48#include "TKey.h"
49#include "TF1.h"
50
51#include <cstdlib>
52
53
54using CLHEP::RandGaussQ;
55using CLHEP::RandFlat;
56
57//
58// Constructor
59//
60TileDigitsFromPulse::TileDigitsFromPulse(const std::string& name, ISvcLocator* pSvcLocator) :
61 AthAlgorithm(name, pSvcLocator)
62{
63
64 declareProperty("ImperfectionMean", m_imperfectionMean = 1.01);
65 declareProperty("ImperfectionRms", m_imperfectionRms = 0.02);
66 declareProperty("InTimeAmp", m_inTimeAmp = 300.);
67 declareProperty("OutOfTimeAmp", m_ootAmp = 150.);
68 declareProperty("InTimeOffset", m_itOffset = 0.);
69 declareProperty("OutOfTimeOffset", m_ootOffset = 50.);
70 declareProperty("OutOfTimeOffsetHistogramFile", m_ootOffsetFileName = "");
71 declareProperty("OutOfTimeOffsetHistogramName", m_ootOffsetHistName = "");
72 declareProperty("UseGaussNoise", m_gaussNoise = kFALSE);
73 declareProperty("GaussNoiseAmpOne", m_GNAmpOne = 1 / 1.039);
74 declareProperty("GaussNoiseSigmaOne", m_GNSigmaOne = 1.6);
75 declareProperty("GaussNoiseAmpTwo", m_GNAmpTwo = 0.039);
76 declareProperty("GaussNoiseSigmaTwo", m_GNSigmaTwo = 3.6);
77 declareProperty("UseInTimeAmpDist", m_useItADist = kFALSE);
78 declareProperty("UseOutOfTimeAmpDist", m_useOotADist = kFALSE);
79 declareProperty("InTimeAmpDistFileName", m_itADistFileName = "");
80 declareProperty("InTimeAmpPulseProb", m_itAPulseProb = 0);
81 declareProperty("OutOfTimeAmpDistFileName", m_ootADistFileName = "");
82 declareProperty("PileUpFraction", m_pileUpFraction = 1);
83 declareProperty("GaussianC2CPhaseVariation", m_gausC2C = 0);
84 declareProperty("ChannelSpecificPedestal", m_chanPed = kFALSE);
85 declareProperty("ChannelSpecificNoise", m_chanNoise = kFALSE);
86 declareProperty("PedestalValueHG", m_ped_HG = 100);
87 declareProperty("PedestalValueLG", m_ped_LG = 100);
88 declareProperty("AmpDistLowerLimit", m_AmpDistLowLim = 135);
89 declareProperty("InTimeAmpDistHistogramName", m_itADistHistName = "h_Eopt_hi");
90 declareProperty("OutOfTimeAmpDistHistogramName", m_ootADistHistName = "h_Eopt_hi");
91
92 declareProperty("SimulatePileUpWithPoiss", m_simPUwPoisson = kFALSE);
93 declareProperty("AvgMuForPileUpSimulation", m_avgMuForPU = 40);
94 declareProperty("PileUpAmpDistFileName", m_pileupAmpDistFileName = "");
95
96 declareProperty("RandomSeed", m_seed = 4357);
97 declareProperty("BunchSpacing", m_BunchSpacing = 25.); // 25, 50 or 75
98 declareProperty("SimulateQIE", m_simQIE = kFALSE);
99 declareProperty("SimulatePulseChain",m_simPulseChain = kFALSE);
100
101 declareProperty("TileInfoName", m_infoName = "TileInfo");
102 declareProperty("TilePhaseII", m_PhaseII = kFALSE);
103 declareProperty("Bigain", m_bigain = kFALSE);
104 declareProperty("NSamples", m_nSamples = 7);
105 declareProperty("NPulses", m_nPul = 21);
106
107 //Initialisations
108 m_ps[0] = new TilePulseShape(msgSvc(), "TilePulseShapeLo"); //Low Gain
109 m_ps[1] = new TilePulseShape(msgSvc(), "TilePulseShapeHi"); //High Gain
110
111
112 m_itFile = new TFile();
113 m_itDist = new TH1F();
114 m_ootFile = new TFile();
115 m_ootDist = new TH1F();
116 m_ootOffsetDist = new TH1F();
117 m_ootOffsetFile = new TFile();
118
119 m_pileup_AmpDistFile = new TFile();
120
121 m_useOffsetHisto = kFALSE;
122
123}
124
126
127 delete m_ootOffsetFile;
128 delete m_ootFile;
129 delete m_itFile;
131
132 delete m_ps[0];
133 delete m_ps[1];
134}
135
136//
137// Alg standard initialize function
138//
140
141 ATH_MSG_DEBUG("in initialize()");
142
143 m_buf = new TileSampleBuffer(m_nSamples, -(m_nSamples-1)*25/2, 25.);
144
145 m_tsg = new TileSampleGenerator(m_ps[0], m_buf, false); //Set third parameter to true for debug of the sum of pulses
146
147 m_nPul_eff = (m_nPul - 1) / 2; //Used for symetrization of PU in computation
148
149 ATH_CHECK(detStore()->retrieve(m_tileHWID, "TileHWID"));
151 m_i_ADCmax = m_tileInfo->ADCmax();
152 ATH_MSG_DEBUG("Max ADC counts TileDigitsFromPulse: " << m_i_ADCmax);
153
155
156 ATH_CHECK(m_digitsContainerKey.initialize());
157 ATH_MSG_INFO("Output digits container: " << m_digitsContainerKey.key());
158
160 ATH_MSG_INFO("Output raw channel container: " << m_rawChannelContainerKey.key());
161
162
163 //Build pulse shapes
164 m_ps[0]->setPulseShape(m_tileInfo->digitsFullShapeLo());
165 m_ps[1]->setPulseShape(m_tileInfo->digitsFullShapeHi());
166
167 m_random = std::make_unique<TRandom3>(m_seed);
168
169 //Initialise distribution histograms if in use
170 if (m_useItADist) {
171 if (m_itADistFileName.size() == 0) {
172 m_itADistFileName = PathResolver::find_file("Distributions_small_h2000_177531_JetTauEtmiss.root", "DATAPATH");
173 if (m_itADistFileName.size() == 0) {
174 ATH_MSG_FATAL("Could not find input file Distributions_small_h2000_177531_JetTauEtmiss.root");
175 return StatusCode::FAILURE;
176 }
177 }
179 return StatusCode::FAILURE;
180 ATH_MSG_DEBUG("Made in-time distribution");
181 } else
182 delete m_itDist;
183
184 if (m_simPUwPoisson){
185
186 if (m_pileupAmpDistFileName.size() == 0) {
187 m_pileupAmpDistFileName = PathResolver::find_file("Distributions_MB_minbias_inelastic_lowjetphoton_e8314_e7400_s3508.root", "DATAPATH");
188 if (m_pileupAmpDistFileName.size() == 0 ) {
189 ATH_MSG_FATAL("Could not find input file Distributions_MB_minbias_inelastic_lowjetphoton_e8314_e7400_s3508.root");
190 return StatusCode::FAILURE;
191 }
192
193 }
195 return StatusCode::FAILURE;
196 ATH_MSG_DEBUG("Made PU amp distributions for each partition and channel");
197
198 }
199
200 if (m_useOotADist) {
201 if (m_ootADistFileName.size() == 0) {
202 m_ootADistFileName = PathResolver::find_file("Distributions_small_h2000_177531_ZeroBias.root", "DATAPATH");
203 if (m_ootADistFileName.size() == 0) {
204 ATH_MSG_FATAL("Could not find input file Distributions_small_h2000_177531_ZeroBias.root");
205 return StatusCode::FAILURE;
206 }
207 }
209 return StatusCode::FAILURE;
210 ATH_MSG_DEBUG("Made Oot distribution");
211 } else
212 delete m_ootDist;
213
214 //Initialise timing offset distribution. If filename is empty, use static offset
215 if (m_ootOffsetFileName.size() != 0) {
216 m_ootOffsetFile = TFile::Open(m_ootOffsetFileName.c_str());
217 if (m_ootOffsetFile->IsZombie()) {
218 ATH_MSG_WARNING("Error reading offset timing distribution from " << m_ootOffsetFileName << ". Using static timing offset.");
219 } else {
220 TKey *key = m_ootOffsetFile->FindKey(m_ootOffsetHistName.c_str());
221 if (key == 0) {
222 ATH_MSG_WARNING("Histogram " << m_ootOffsetHistName << " not found in file " << m_ootOffsetFileName << ". Using static timing offset.");
223 } else {
225 m_useOffsetHisto = kTRUE;
226 }
227 }
228 }
229
230 //Start the random number service used to create channel specific noise
231 if (!m_rndmSvc.retrieve().isSuccess()) {
232 ATH_MSG_FATAL("Could not initialize find Random Number Service.");
233 return StatusCode::FAILURE;
234 }
235 if (m_chanNoise)
236 m_gaussNoise = kFALSE; //Make sure channel noise overrides gaussian noise.
237
238 m_PUAmp.clear();
239 m_PUAmp.resize(4);
240 for (int ros = 1; ros < 5; ++ros){
241 m_PUAmp[ros-1].clear();
242 m_PUAmp[ros-1].resize(64);
243
244 for (int drawer = 0; drawer < 64; ++drawer){
245 m_PUAmp[ros-1][drawer].clear();
246 m_PUAmp[ros-1][drawer].resize(48);
247 for (int channel = 0; channel < 48; channel++){
248 m_PUAmp[ros-1][drawer][channel].clear();
249 m_PUAmp[ros-1][drawer][channel].resize(m_nPul);
250 }
251 }
252 }
253
254 for (int ros = 1; ros < 5; ++ros) { // initialize the vector of PU amplitudes
255 for (int drawer = 0; drawer < 64; ++drawer){
256 for (int channel = 0; channel < 48; ++channel) {
257 addPileUp(m_inTimeAmp, 1, ros, drawer, channel); // Initialized for HG, for LG use the same divided by the HG/LG ratio
258 }
259 }
260 }
261
262 ATH_MSG_DEBUG("initialize() successful");
263
264 return StatusCode::SUCCESS;
265}
266/*==========================================================================*/
267//
268// Begin Execution Phase.
269//
270StatusCode TileDigitsFromPulse::execute(const EventContext& ctx) {
271
272 ATH_MSG_DEBUG("in execute()");
273
274
275 // Prepare RNG service
276 ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this, m_randomStreamName);
277 rngWrapper->setSeed( m_randomStreamName, ctx );
278 CLHEP::HepRandomEngine* rndmEngine = rngWrapper->getEngine(ctx);
279
280 // Create new container for digits
281 auto digitsContainer = std::make_unique<TileMutableDigitsContainer>(true,
285
286 ATH_CHECK( digitsContainer->status() );
287
288 //Create RawChannel for truth values.
289 auto rawChannelContainer = std::make_unique<TileMutableRawChannelContainer>(true, m_rChType, m_rChUnit);
290 ATH_CHECK( rawChannelContainer->status() );
291
292 DataPool < TileDigits > tileDigitsPool(m_tileHWID->adc_hash_max());
293
294 double tFit = 0, ped = 100; //Settings for simulation
295
296 TF1 *pdf = new TF1();
297 TF1 *pdf_PhaseI = new TF1();
298 TF1 *pdf_lo = new TF1();
299 TF1 *pdf_hi = new TF1();
300 if (!m_simQIE) {
301
302
303 if(m_PhaseII){
304 Double_t sigma_lo = 1; //Noise value obtained from ATL-COM-TILECAL-2020-031
305 pdf_lo = new TF1("pdf_lo","(1/(sqrt(2*pi)*[0])) * (exp(-0.5*(x/[0])**2)/(sqrt(2*pi)*[0]))", -100, 100);
306 pdf_lo->SetParameter(0,sigma_lo);
307
308 Double_t sigma_hi = 2.5; //Noise value obtained from ATL-COM-TILECAL-2020-031
309 pdf_hi = new TF1("pdf_hi","(1/(sqrt(2*pi)*[0])) * (exp(-0.5*(x/[0])**2)/(sqrt(2*pi)*[0]))", -100, 100);
310 pdf_hi->SetParameter(0,sigma_hi);
311 }
312 else{
313 //Noise pdf for general noise. Maybe use as a member and put in init.
314 //pdf = new TF1("pdf", "[0] * (Gaus(x,0,[1]) + [2] * Gaus(x,0,[3]))", -100., 100.); //Root goes not like "Gaus"
315
316 pdf_PhaseI = new TF1("pdf_PhaseI", "[0] * (exp(-0.5*(x/[1])**2)/(sqrt(2*pi)*[1]) + [2] *exp(-0.5*(x/[3])**2)/(sqrt(2*pi)*[3]))", -100., 100.);
317 pdf_PhaseI->SetParameters(m_GNAmpOne, m_GNSigmaOne, m_GNAmpTwo, m_GNSigmaTwo);
318 }
319 }
320
321 std::vector<float> samples(m_nSamples);
322
323 double Rndm[16]; // Can't use variable size array,
324 double Rndm_dG[1]; // uniform random number for the double gaussian
325
326 ATH_MSG_DEBUG("Starting loop");
327 int gain = 1;
328 double n_inTimeAmp = 0.0;
329 float sample = 0.0;
330
331 for (int ros = 1; ros < 5; ++ros) {
332 for (int drawer = 0; drawer < 64; ++drawer) {
333 unsigned int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
334 for (int channel = 0; channel < 48; ++channel) {
335
336 if (!m_simQIE && !m_simPulseChain) { //3-in-1 or FENICS is simulated below
337
338 if(m_PhaseII){
339 ATH_MSG_VERBOSE("executing FENICS code");
340 }
341 else{
342 ATH_MSG_VERBOSE("executing 3-in-1 code");
343 }
344
345
346 bool isHGSaturated = false;
347
348 for (int igain = 1; igain >= 0; igain--) {
349
350 gain = igain;
351 if (m_chanPed){
352 ped = m_tileToolNoiseSample->getPed(drawerIdx, channel, gain, TileRawChannelUnit::ADCcounts, ctx);
353 }
354 else{
355 ped = (gain == 1) ? m_ped_HG : m_ped_LG;
356 }
357
358 if (gain == 1) {
359 n_inTimeAmp = m_useItADist ? m_itDist->GetRandom() : m_inTimeAmp;
360
361 if (m_random->Rndm() >= m_pileUpFraction){
362 m_ootAmp = 0; //Set oot amplitude to 0 if no pile-up.
363 }
364 tFit = m_random->Gaus(0., m_gausC2C); //C2C phase variation
365 double deformatedTime = m_random->Gaus(m_imperfectionMean, m_imperfectionRms); //Widening of pulseshape
366 m_ps[gain]->scalePulse(deformatedTime, deformatedTime); // Deformation of pulse shape by changing its width
367 //if(m_useOffsetHisto) m_ootOffset = m_ootOffsetDist->GetRandom(); //OLD Remove for 7 samples -> BunchSpacing
368
369 // Make sure m_PUAmp[ros-1][drawer][channel] has m_nPul elements, all zero
370 m_PUAmp[ros-1][drawer][channel].assign(m_nPul, 0.0);
371
372 // Fill amplitudes (including pile-up) for HG
373 addPileUp(n_inTimeAmp, gain, ros, drawer, channel);
374
375 } else {
376 double deformatedTime = m_random->Gaus(m_imperfectionMean, m_imperfectionRms); //Widening of pulseshape
377 m_ps[gain]->scalePulse(deformatedTime, deformatedTime); // Deformation of pulse shape by changing its width
378
379 double scaleFactor = (m_PhaseII ? 40.0 : 64.0);
380 n_inTimeAmp /= scaleFactor;
381 for (auto &ampValue : m_PUAmp[ros-1][drawer][channel]) {
382 ampValue /= scaleFactor;
383 }
384 }
385
386 if(m_PhaseII && m_gaussNoise){
387 pdf = (gain==1) ? pdf_hi : pdf_lo;
388 }
389 else if(m_gaussNoise){
390 pdf = pdf_PhaseI;
391 }
392
393 m_tsg->setPulseShape(m_ps[gain]);
394 m_tsg->fillNSamples(tFit, ped, n_inTimeAmp, m_PUAmp[ros-1][drawer][channel], pdf, m_gaussNoise, m_itOffset, m_nSamples, m_nPul); // Sum of Intime + PU pulses
395
396 samples.clear();
397 samples.resize(m_nSamples);
398 m_buf->getValueVector(samples);
399
400 if (m_chanNoise) {
401 double Hfn1 = m_tileToolNoiseSample->getHfn1(drawerIdx, channel, gain, ctx);
402 double Hfn2 = m_tileToolNoiseSample->getHfn2(drawerIdx, channel, gain, ctx);
403 double Norm = m_tileToolNoiseSample->getHfnNorm(drawerIdx, channel, gain, ctx);
404 RandGaussQ::shootArray(rndmEngine, samples.size(), Rndm, 0.0, 1.0);
405 RandFlat::shootArray(rndmEngine, 1, Rndm_dG, 0.0, 1.0);
406 for (unsigned int js = 0; js < samples.size(); ++js) {
407 //using the same gaussian(sigma) for all samples in one channel in one event
408 if (Rndm_dG[0] < Norm)
409 samples[js] += (float) Hfn1 * Rndm[js];
410 else
411 samples[js] += (float) Hfn2 * Rndm[js];
412 }
413 }
414
415 for (unsigned int i = 0; i < samples.size(); ++i) {
416 if (samples[i] >= m_i_ADCmax){
417 isHGSaturated = true;
418 if(m_bigain) samples[i]=m_i_ADCmax;
419 }
420
421 }
422
423 if(!m_bigain && !isHGSaturated){
424 break;
425 }
426
427 ATH_MSG_VERBOSE("New ADC " << ros << "/" << drawer << "/" << channel << "/ saving gain " << gain);
428
429 TileDigits * digit = tileDigitsPool.nextElementPtr();
430 *digit = TileDigits (m_tileHWID->adc_id(ros, drawer, channel, gain), samples);
431
432 ATH_CHECK( digitsContainer->push_back(digit) );
433
434 auto rawChannel = std::make_unique<TileRawChannel>(digit->adc_HWID(),
435 n_inTimeAmp,
436 tFit,
437 m_ootAmp,
439
440 ATH_CHECK( rawChannelContainer->push_back(std::move(rawChannel)) );
441
442 }
443
444 if(!m_bigain){
445 ATH_MSG_VERBOSE("New ADC " << ros << "/" << drawer << "/" << channel << "/ saving gain " << gain);
446
447 TileDigits * digit = tileDigitsPool.nextElementPtr();
448 *digit = TileDigits (m_tileHWID->adc_id(ros, drawer, channel, gain), std::move(samples));
449
450 ATH_CHECK( digitsContainer->push_back(digit) );
451
452 auto rawChannel = std::make_unique<TileRawChannel>(digit->adc_HWID(),
453 n_inTimeAmp,
454 tFit,
455 m_ootAmp,
457
458 ATH_CHECK( rawChannelContainer->push_back(std::move(rawChannel)) );
459 }
460
461 } else if (m_simQIE) { //QIE is simulated here --------------------------------------------
462
463 //ATH_MSG_DEBUG("executing QIE code");
464
465 gain = 1; //This is just a place holder. The gain is not used in QIE.
466 n_inTimeAmp = m_useItADist ? m_itDist->GetRandom() : m_inTimeAmp;
467 //if (random->Rndm() >= m_pileUpFraction) //m_pileUpFraction is 1 by default
468 m_ootAmp = 0; //Set oot amplitude to 0 if no pile-up.
469 tFit = 0; //TODO: Introduce jitter of the PMT pulse; random->Gaus(0., m_gausC2C); //C2C phase variation
470
471 //Pileup samples
472 //m_PUAmp.clear();
473 //m_PUAmp.resize(nPul);
474 float my_PUAmp[7] = {0}; //I use an array to store the energies/charges of the out-of-time pulses
475
476 for (int i = 0; i < 7; i++)
477 if ((((i - 3) * 25) % (int) m_BunchSpacing) == 0) {
478 if (i != 3) { //index 3 corresponds to the in-time pulse, the signal
479 my_PUAmp[i] = m_useOotADist ? m_ootDist->GetRandom() : m_ootAmp; //out-of-time pulses
480 } else {
481 my_PUAmp[i] = 0;
482 }
483 }
484
485 //fill7SamplesQIE(float t0, float amp_it, float *amp_pu, bool addNoise);
486 m_tsg->fill7SamplesQIE((float) n_inTimeAmp, my_PUAmp); // Sum of In time + out-of-time PU pulses
487
488 samples.clear();
489 samples.resize(m_nSamples);
490 m_buf->getValueVector(samples);
491
492 ATH_MSG_VERBOSE("New ADC " << ros << "/" << drawer << "/" << channel << "/ saving gain " << gain);
493
494 TileDigits * digit = tileDigitsPool.nextElementPtr();
495 *digit = TileDigits (m_tileHWID->adc_id(ros, drawer, channel, gain),
496 std::move(samples));
497
498 ATH_CHECK( digitsContainer->push_back(digit) );
499
500 auto rawChannel = std::make_unique<TileRawChannel>(digit->adc_HWID(),
501 n_inTimeAmp,
502 tFit,
503 m_ootAmp,
505
506 ATH_CHECK( rawChannelContainer->push_back(std::move(rawChannel)) );
507 }
508 else if (m_simPulseChain) {
509 ATH_MSG_VERBOSE("executing chain-of-pulses code");
510
511 bool isHGSaturated = false;
512
513 for (int igain = 1; igain >= 0; --igain) {
514 gain = igain;
515 n_inTimeAmp = 0.0;
516 m_ootAmp = 0.0;
517 m_ootOffset = 0.0;
518
519 if (m_random->Rndm() < m_itAPulseProb){
520 n_inTimeAmp = m_useItADist ? m_itDist->GetRandom() : m_inTimeAmp;
521 } else{
522 n_inTimeAmp = 0;
523 }
524
525 // PDF logic for noise
526 if (m_gaussNoise) {
527 if (m_PhaseII) {
528 pdf = (gain == 1) ? pdf_hi : pdf_lo;
529 } else {
530 pdf = pdf_PhaseI;
531 }
532 }
533
534 if (gain == 1) {
535 ped = m_chanPed
536 ? m_tileToolNoiseSample->getPed(drawerIdx, channel, gain,
538 : m_ped_HG;
539
540 tFit = m_random->Gaus(0., m_gausC2C);
541 double deformatedTime = m_random->Gaus(m_imperfectionMean, m_imperfectionRms);
542 m_ps[gain]->scalePulse(deformatedTime, deformatedTime);
543
544 // Shift the stored pulses to simulate consecutive BC
545 m_PUAmp[ros-1][drawer][channel].pop_back();
546 m_PUAmp[ros-1][drawer][channel].insert(m_PUAmp[ros-1][drawer][channel].begin(), 0);
547
548 // m_sample_tru is the amplitude for the central BC
549 m_sample_tru = m_PUAmp[ros-1][drawer][channel][(m_nPul - 1) / 2];
550
551 // Fill the new BC at the front
552 addPileUpSample(gain, ros, drawer, channel);
553 m_PUAmp[ros-1][drawer][channel].front() += n_inTimeAmp; // Add amplitude from in-time pulse to true-amp vector
554
555 sample = m_tsg->fillSample(tFit, ped,
556 m_PUAmp[ros-1][drawer][channel],
557 pdf, m_gaussNoise,
558 (int)m_PUAmp[ros-1][drawer][channel].size(),
559 gain);
560 } else {
561 // Low gain
562 ped = m_chanPed
563 ? m_tileToolNoiseSample->getPed(drawerIdx, channel, gain,
565 : m_ped_LG;
566
567 sample = m_tsg->fillSample(tFit, ped,
568 m_PUAmp[ros-1][drawer][channel],
569 pdf, m_gaussNoise,
570 (int)m_PUAmp[ros-1][drawer][channel].size(),
571 gain);
572
573 // Scale truth amplitude from HG to LG
574 if (m_PhaseII) {
575 m_sample_tru /= 40.0;
576 } else {
577 m_sample_tru /= 64.0;
578 }
579 }
580
581 // Clip the sample
582 if (sample < 0.0) {
583 sample = 0.0;
584 } else if (sample >= m_i_ADCmax) {
585 isHGSaturated = true;
586 if (m_bigain) sample = m_i_ADCmax;
587 }
588
589 samples.clear();
590 samples.push_back(sample);
591
592 ATH_MSG_VERBOSE("New chain ADC " << ros << "/" << drawer << "/" << channel << " - saving gain " << gain);
593
594 TileDigits* digit = tileDigitsPool.nextElementPtr();
595 *digit = TileDigits(m_tileHWID->adc_id(ros, drawer, channel, gain),
596 std::move(samples));
597 ATH_CHECK(digitsContainer->push_back(digit));
598
599 // Use the “truth” amplitude for rawChannel
600 auto rawChannel = std::make_unique<TileRawChannel>(
601 digit->adc_HWID(),
603 tFit,
604 m_ootAmp,
605 ped);
606 ATH_CHECK(rawChannelContainer->push_back(std::move(rawChannel)));
607
608 // If not bigain, break if HG didn't saturate
609 if (!m_bigain && !isHGSaturated) {
610 break;
611 }
612 }
613 }
614 }
615 }
616 }
617
619 ATH_CHECK( rawChannelCnt.record(std::move(rawChannelContainer)) );
620
622 ATH_CHECK( digitsCnt.record(std::move(digitsContainer)) );
623
624 if (!m_simQIE) {
625 //delete pdf;
626 delete pdf_PhaseI;
627 delete pdf_hi;
628 delete pdf_lo;
629 }
630
631 ATH_MSG_DEBUG("Execution completed");
632
633 return StatusCode::SUCCESS;
634}
635
637 ATH_MSG_DEBUG("in finalize()");
638 delete m_buf;
639 delete m_tsg;
640
641
642 if (m_useItADist)
643 m_itFile->Close();
644 if (m_useOotADist)
645 m_ootFile->Close();
646 if (m_simPUwPoisson)
647 m_pileup_AmpDistFile->Close();
648
649 return StatusCode::SUCCESS;
650}
651
652bool TileDigitsFromPulse::makeDist(TFile*& file, TH1F*& hist, const std::string& fileName, const std::string& histName) {
653 file = new TFile(fileName.c_str());
654 if (file->IsZombie()) {
655 ATH_MSG_FATAL("Error reading amplitude distribution from " << fileName << ".");
656 return kFALSE;
657 }
658 TKey *key = file->FindKey(histName.c_str());
659 if (key == 0) {
660 ATH_MSG_FATAL("Could not find histogram " << histName << " in file " << fileName << ".");
661 return kFALSE;
662 }
663 hist = (TH1F*) file->Get(histName.c_str());
664 for (int i = 0; i < m_AmpDistLowLim; i++)
665 hist->SetBinContent(i, 0.); // Puts a cut on the amplitude distribution.
666 return kTRUE;
667
668}
669
670bool TileDigitsFromPulse::makeDist(TFile*& file, std::vector<std::vector<TH1F*>>& hists, const std::string& fileName) {
671
672 std::string histName;
673 TKey *key;
674 TH1F* hist;
675
676 file = new TFile(fileName.c_str());
677 if (file->IsZombie()) {
678 ATH_MSG_FATAL("Error reading amplitude distributions from " << fileName << ".");
679 return kFALSE;
680 }
681
682 for(int ros=0; ros<4; ros++){
683
684 hists.push_back(std::vector<TH1F*>());
685 for(int channel=0; channel<48; channel++){
686
687 histName = "ene_ros_" + std::to_string(ros+1) + "_channel_" + std::to_string(channel+1);
688
689 key = file->FindKey(histName.c_str());
690 if (key == 0) {
691 ATH_MSG_FATAL("Could not find histogram " << histName << " in file " << fileName << ".");
692 return kFALSE;
693 }
694
695 hist = (TH1F*) file->Get(histName.c_str());
696
697 for (int i = 0; i < m_AmpDistLowLim; i++)
698 hist->SetBinContent(i, 0.); // Puts a cut on the amplitude distribution.
699
700 hists[ros].push_back(hist);
701 hist->Clear();
702 }
703 }
704
705 return kTRUE;
706}
707
708void TileDigitsFromPulse::addPileUp(double &n_inTimeAmp, int gain, int ros, int drawer, int channel) {
709 //Pileup samples
710 double amp_1;
711 double amp_2;
712 double mu = 0; //Interaction per bunch crossing for PU simulation
713 if(gain == 1){
714 for (int i = 0; i <= m_nPul_eff; i++) {
715 if (((i * 25) % m_BunchSpacing) == 0) {
716 if(m_simPUwPoisson){
717 mu=m_random->Poisson(m_avgMuForPU);
718 ATH_MSG_VERBOSE("Effective pulse number " << i);
719 ATH_MSG_VERBOSE("Number of interactions for simulation: " << mu );
720
721 for (int imu = 0; imu<mu; imu++){
722
723 if (m_random->Rndm() < m_pileUpFraction){
724 amp_1 = m_pileup_AmpDists[ros-1][channel]->GetRandom();
725 }
726 else{
727 amp_1 = 0;
728 }
729
730 if (m_random->Rndm() < m_pileUpFraction){
731 amp_2 = m_pileup_AmpDists[ros-1][channel]->GetRandom();
732 }
733 else{
734 amp_2 = 0;
735 }
736
737 ATH_MSG_VERBOSE("Random amplitudes for PU: " << amp_1 << " " << amp_2);
738 if(i==0){
739 m_PUAmp[ros-1][drawer][channel][m_nPul_eff] += amp_1;
740 }
741 else{
742 m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] += amp_1;
743 m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] += amp_2;
744 }
745 }
746
747 if(m_PUAmp[ros-1][drawer][channel][m_nPul_eff] < 0) m_PUAmp[ros-1][drawer][channel][m_nPul_eff] = 0;
748 if(m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] < 0) m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] = 0;
749 if(m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] < 0) m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] = 0;
750
751 ATH_MSG_VERBOSE("Final amplitudes for pulse " << m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] << " " << m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i]);
752 }
753 else{
754 m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] = m_useOotADist ? m_ootDist->GetRandom() : m_ootAmp;
755 m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] = m_useOotADist ? m_ootDist->GetRandom() : m_ootAmp;
756 }
757
758 if(m_simPulseChain){ // Special treatment for pulse-chain simulation, add in-time pulses when initializing true-amp vector
759 if (m_random->Rndm() < m_itAPulseProb){
760 amp_1 = m_useItADist ? m_itDist->GetRandom() : m_inTimeAmp;
761 } else{
762 amp_1 = 0;
763 }
764
765 if (m_random->Rndm() < m_itAPulseProb){
766 amp_2 = m_useItADist ? m_itDist->GetRandom() : m_inTimeAmp;
767 } else{
768 amp_2 = 0;
769 }
770
771 if(i==0){
772 m_PUAmp[ros-1][drawer][channel][m_nPul_eff] += amp_1;
773 }
774 else{
775 m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] += amp_1;
776 m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] += amp_2;
777 }
778 }
779 } else {
780 m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] = 0;
781 m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] = 0;
782 }
783 }
784 }
785 else if (gain == 0)
786 {
787 double scaleFactor = m_PhaseII ? 40 : 64;
788 n_inTimeAmp /= scaleFactor;
789 for (int i = 0; i <= m_nPul_eff; i++) {
790 m_PUAmp[ros-1][drawer][channel][m_nPul_eff + i] /= scaleFactor;
791 m_PUAmp[ros-1][drawer][channel][m_nPul_eff - i] /= scaleFactor;
792 }
793 }
794}
795
796void TileDigitsFromPulse::addPileUpSample(int gain, int ros, int drawer, int channel) {
797
798 double amp = 0;
799 double mu = 0; //Interaction per bunch crossing for PU simulation
800
801 auto random = std::make_unique<TRandom3>(m_seed);
802
803 mu=random->Poisson(m_avgMuForPU);
804
805 if(gain == 1){
806 for (int imu = 0; imu<mu; imu++){
807 if (random->Rndm() < m_pileUpFraction){
808 amp = m_pileup_AmpDists[ros-1][channel]->GetRandom();
809 }
810 else{
811 amp = 0;
812 }
813
814 m_PUAmp[ros-1][drawer][channel].front() += amp;
815 }
816 }
817 else if (gain == 0)
818 {
819 if(!m_PhaseII){
820 m_PUAmp[ros-1][drawer][channel].front() /= 64;
821 }
822 else{
823 m_PUAmp[ros-1][drawer][channel].front() /= 40;
824 }
825 }
826
827 if(m_PUAmp[ros-1][drawer][channel].front() < 0) m_PUAmp[ros-1][drawer][channel].front() = 0;
828}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
size_t size() const
Number of registered mappings.
Helper for holding non-const raw data prior to recording in SG.
Helper for holding non-const raw data prior to recording in SG.
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition RNGWrapper.h:154
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:108
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const ServiceHandle< StoreGateSvc > & detStore() const
pointer nextElementPtr()
obtain the next available element in pool by pointer pool is resized if its limit has been reached On...
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
TFile * m_pileup_AmpDistFile
File containing amplitude histograms for PU pulses.
bool m_useOotADist
Set to TRUE in order to use a distribution for the out-of-time amplitude instead of a constant value.
TFile * m_itFile
File that holds the distribution of in-time amplitudes.
SG::WriteHandleKey< TileRawChannelContainer > m_rawChannelContainerKey
std::string m_itADistHistName
Name of histogram for in-time amplitude distribution.
std::string m_itADistFileName
Filename of file to use for amplitude distribution of in-time pulses.
bool m_chanNoise
Add channel specific noise.
const TileHWID * m_tileHWID
virtual StatusCode initialize() override
initialize method
virtual StatusCode finalize() override
finalize method
double m_ootAmp
Amplitude of out-of-time pulse.
std::string m_ootADistFileName
Filename of file to use for amplitude distribution of out-of-time pulses.
TH1F * m_ootDist
Histogram to hold the distribution of out-of-time amplitudes.
std::string m_ootADistHistName
Name of histogram for out-of-time amplitude distribution.
bool m_simPulseChain
Simulate continous output of readout for HL-LHC paradigm.
TFile * m_ootFile
File that holds the distribution of out-of-time amplitudes.
TileFragHash::TYPE m_rChType
Type of TileRawChannels (Digitizar, OF1, OF2, Fit, etc.)(see TileFragHash.h).
TileSampleBuffer * m_buf
Buffer class to hold generated pulses.
ToolHandle< TileCondToolNoiseSample > m_tileToolNoiseSample
virtual StatusCode execute(const EventContext &ctx) override
execute method
TFile * m_ootOffsetFile
File that holds the distribution of out-of-time timing offsets.
double m_itOffset
In-time pulse offset from nominal time.
void addPileUpSample(int gain, int ros, int drawer, int channel)
Fill only a BC with pile-up amplitude.
std::vector< std::vector< std::vector< std::vector< float > > > > m_PUAmp
std::unique_ptr< TRandom3 > m_random
double m_ped_HG
Pedestal value for HG if specific channel pedestal is not used.
double m_GNAmpTwo
Amplitude of second gaussian of double gaussian noise.
float m_gausC2C
RMS for the in-time pulse offset (channel-to-channel phase variation).
std::string m_ootOffsetFileName
File name for offset timing distribution histogram.
bool m_useOffsetHisto
Internally used to keep track of wether a histogram has been opened or not.
TileRawChannelUnit::UNIT m_rChUnit
Units used for the TileRawChannels (ADC, pCb, etc.)(see TileInfo.h).
const TileInfo * m_tileInfo
int m_nPul
number of pileup pulses
double m_GNAmpOne
Amplitude of first gaussian of double gaussian noise.
double m_ootOffset
Out-of-time pulse offset from nominal time.
TH1F * m_ootOffsetDist
Histogram to hold the distribution of out-of-time timing offsets.
SG::WriteHandleKey< TileDigitsContainer > m_digitsContainerKey
TilePulseShape * m_ps[2]
Class for defining pulse.
double m_GNSigmaTwo
Standard deviation of second gaussian of double gaussian noise.
ServiceHandle< IAthRNGSvc > m_rndmSvc
Random number service to use.
TileSampleGenerator * m_tsg
Pulse generating class.
double m_itAPulseProb
Probability to add an in-time pulse.
bool m_simQIE
Raw PMT pulses are generated if the option is set to true.
double m_imperfectionMean
Mean value of pulse shape broadening.
Gaudi::Property< std::string > m_randomStreamName
Random Stream Name.
std::string m_pileupAmpDistFileName
Filename for PU amplitude distribution histograms.
bool makeDist(TFile *&file, TH1F *&hist, const std::string &fileName, const std::string &histName="h_Eopt_hi")
Method to read distribution from file.
TH1F * m_itDist
Histogram to hold the distribution of in-time amplitudes.
double m_GNSigmaOne
Standard deviation of first gaussian of double gaussian noise.
int m_AmpDistLowLim
Set all bins to the left of this bin to 0 in the amplitude distribution histograms.
double m_ped_LG
Pedestal value for LG if specific channel pedestal is not used.
double m_imperfectionRms
RMS of pulse shape broadening.
float m_pileUpFraction
Probability that an out-of-time component will be added.
TileDigitsFromPulse(const std::string &name, ISvcLocator *pSvcLocator)
std::vector< std::vector< TH1F * > > m_pileup_AmpDists
Matrix of PU amplitude distribution histograms (PU per partition and channel).
bool m_useItADist
Set to TRUE in order to use a distribution for the in-time amplitude instead of a constant value.
bool m_chanPed
Use channel specific pedestal value if true.
void addPileUp(double &n_inTimeAmp, int gain, int ros, int drawer, int channel)
Fill vector with pile-up amplitudes.
bool m_gaussNoise
Set to TRUE in order to create noise from double gaussian.
std::string m_ootOffsetHistName
Name of the histogram for timing offset distribution.
int m_nSamples
number of read out samples
int m_BunchSpacing
Time between pulses in ms 25, 50 or 75.
double m_inTimeAmp
Amplitude of in-time pulse.
void Norm(TH1 *h, double scale)
Definition computils.cxx:67
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
TFile * file