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