44 #include "GaudiKernel/ThreadLocalContext.h"
51 #include <CLHEP/Random/Randomize.h>
55 #include "TDecompChol.h"
60 using CLHEP::RandGaussQ;
61 using CLHEP::RandFlat;
115 ATH_MSG_DEBUG(
"Initializing pulse shape conditions object");
147 ATH_MSG_INFO(
"Pileup and/or noise added by overlaying digits of random events");
153 ATH_MSG_INFO(
"PileUpMergeSvc successfully initialized");
164 msg(MSG::INFO) <<
"Obtained info from TileInfo" <<
endmsg;
165 msg(MSG::INFO) <<
"tileNoise=" << ((
m_tileNoise) ?
"true" :
"false")
167 <<
", tileThresh=" << ((
m_tileThresh) ?
"true" :
"false");
178 ATH_MSG_INFO(
"Create all channels without noise: true");
189 ATH_MSG_INFO(
"Keep digits from MBTS with original G4 hit energy above "
217 const int nchMax = 48;
220 <<
" nchMax=" << nchMax
226 for (
int dr = 0;
dr < ndrawers; ++
dr) {
231 std::unique_ptr<HWIdentifier[]>& adc_ids =
m_all_ids.back();
239 if (drawerIdx != (
int)idhash) {
241 <<
" hash " << idhash <<
" NOT EQUAL to idx " << drawerIdx);
244 <<
" hash " << idhash <<
endmsg;
247 for (
int ch = 0;
ch < nchMax; ++
ch) {
259 ATH_MSG_INFO(
"TileDigitsMaker initialization completed");
261 return StatusCode::SUCCESS;
270 CLHEP::HepRandomEngine* rngEngine =
nullptr;
286 const int nchMax = 48;
287 for (
int dr = 0;
dr < ndrawers; ++
dr) {
295 for (
int ch = 0;
ch < nchMax; ++
ch) {
305 <<
" pedHi="<< pedSimHi
306 <<
" pedLo="<< pedSimLo
307 <<
" rmsHi="<< sigmaHi_Hfn1 <<
"," << sigmaHi_Hfn2 <<
"," << sigmaHi_Norm
308 <<
" rmsLo="<< sigmaLo_Hfn1 <<
"," << sigmaLo_Hfn2 <<
"," << sigmaLo_Norm);
341 double echtot_Acc = 0.;
342 double echint_Acc = 0.;
343 double echtot_Cut = 0.;
344 double echint_Cut = 0.;
351 auto digitsContainer = std::make_unique<TileMutableDigitsContainer>(
true,
356 std::unique_ptr<TileMutableDigitsContainer> digitsContainer_DigiHSTruth;
358 digitsContainer_DigiHSTruth = std::make_unique<TileMutableDigitsContainer>(
true,
364 std::unique_ptr<TileMutableDigitsContainer> filteredContainer;
366 filteredContainer = std::make_unique<TileMutableDigitsContainer>(
true,
376 const int nchMax = 48;
377 std::vector<int>
igain(nchMax, -1);
378 std::vector<int> ntot_ch(nchMax, 0);
379 std::vector<double> ech_tot(nchMax, 0.0);
380 std::vector<double> ech_int(nchMax, 0);
381 std::vector<double> ech_int_DigiHSTruth(nchMax, 0);
382 std::vector<int> over_gain(nchMax, -1);
386 std::vector<float> digitsBufferLo(
m_nSamples);
387 std::vector<float> digitsBuffer_DigiHSTruth(
m_nSamples);
388 std::vector<float> digitsBufferLo_DigiHSTruth(
m_nSamples);
390 std::vector<double> emptyBuffer;
391 std::vector<std::vector<double>> drawerBufferHi(nchMax, std::vector<double>(
m_nSamples));
392 std::vector<std::vector<double>> drawerBufferLo(nchMax, std::vector<double>(
m_nSamples));
394 std::vector<std::vector<double>> drawerBufferHi_DigiHSTruth;
395 std::vector<std::vector<double>> drawerBufferLo_DigiHSTruth;
397 drawerBufferHi_DigiHSTruth.resize(nchMax, std::vector<double>(
m_nSamples));
398 drawerBufferLo_DigiHSTruth.resize(nchMax, std::vector<double>(
m_nSamples));
404 Bool_t coherNoiseHi =
false;
405 Bool_t coherNoiseLo =
false;
406 TMatrixD CorrWeightHi;
407 TMatrixD CorrWeightLo;
408 std::vector<std::unique_ptr<double[]>> CorrRndmVec;
409 std::vector<std::unique_ptr<double[]>> CorrRndmVecLo;
421 TileMutableDigitsContainer::const_iterator collItrRndm;
422 TileMutableDigitsContainer::const_iterator lastCollRndm;
423 std::unique_ptr<TileMutableDigitsContainer> backgroundDigitContainer{};
425 backgroundDigitContainer = std::make_unique<TileMutableDigitsContainer>(
true,
428 ATH_CHECK( backgroundDigitContainer->status() );
432 TimedDigitContList digitContList;
437 if (digitContList.size() == 0) {
439 return StatusCode::SUCCESS;
443 for (
const auto* digitCollection : *(iTzeroDigitCont->second)) {
444 for (
const auto*
digit : *digitCollection) {
445 auto pDigits = std::make_unique<TileDigits>(*
digit);
446 ATH_CHECK(backgroundDigitContainer->push_back(std::move(pDigits)));
452 if (tileDigitsContainerHandle.
isValid()) {
453 for (
const auto* digitCollection : *tileDigitsContainerHandle) {
454 for (
const auto*
digit : *digitCollection) {
455 auto pDigits = std::make_unique<TileDigits>(*
digit);
456 ATH_CHECK(backgroundDigitContainer->push_back(std::move(pDigits)));
461 ATH_MSG_ERROR(
"ReadHandle to Background Digits is invalid.");
462 return StatusCode::FAILURE;
466 collItrRndm = backgroundDigitContainer->begin();
467 lastCollRndm = backgroundDigitContainer->end();
487 dqStatus = DQstatusHandle.
get();
494 badChannels = badChannelsHandle.
retrieve();
520 ++collItr_DigiHSTruth;
526 const std::unique_ptr<HWIdentifier[]>& adc_ids =
m_all_ids[idhash];
534 std::fill(over_gain.begin(), over_gain.end(), -1);
539 std::fill(ech_tot.begin(), ech_tot.end(), 0.0);
540 std::fill(ech_int.begin(), ech_int.end(), 0.0);
541 std::fill(ntot_ch.begin(), ntot_ch.end(), 0);
544 std::vector<std::reference_wrapper<std::vector<std::vector<double>>>> drawerBuffers{drawerBufferHi, drawerBufferLo};
546 drawerBuffers.push_back(drawerBufferHi_DigiHSTruth);
547 drawerBuffers.push_back(drawerBufferLo_DigiHSTruth);
549 for (std::vector<std::vector<double>>& drawerBuffer : drawerBuffers) {
550 for (std::vector<double>& digitsBuffer : drawerBuffer) {
551 std::fill(digitsBuffer.begin(), digitsBuffer.end(), 0);
558 igain,
ros,
drawer, drawerIdx, over_gain, *emScale, *sampleNoise, dqStatus, badChannels));
562 std::vector<bool> signal_in_channel(nchMax,
false);
563 std::vector<bool> signal_in_channel_DigiHSTruth(nchMax,
false);
565 igain, over_gain, ech_int, signal_in_channel, *emScale, *samplingFraction, pulse));
568 igain, over_gain, ech_int_DigiHSTruth, signal_in_channel_DigiHSTruth, *emScale, *samplingFraction, pulse));
574 for (
int ich = 0; ich < nchMax; ++ich) {
575 if (
igain[ich] > -1) {
576 std::vector<double>& digitSamplesHi = drawerBufferHi[ich];
577 std::vector<double>& digitSamplesLo = drawerBufferLo[ich];
579 <<
" nhit=" << ntot_ch[ich]
580 <<
" e_ch=" << ech_tot[ich]
581 <<
" AinTHi=" << digitSamplesHi[
m_iTrig]
605 <<
" with " << nchMax <<
" channels and "
624 double* RndmVec = CorrRndmVec[
k].get();
625 RandGaussQ::shootArray(rngEngine, nchMax, RndmVec, 0.0, 1.0);
630 double * RndmVecLo = CorrRndmVecLo[
k].get();
631 RandGaussQ::shootArray(rngEngine, nchMax, RndmVecLo, 0.0, 1.0);
638 for (
int ich = 0; ich < nchMax; ++ich) {
649 <<
" PMT " << (pmt_id.
is_valid() ?
m_tileID->
to_string(pmt_id,-1) : (signal_in_channel[ich] ?
"fake gap" :
"not connected"))
650 <<
" gain=" <<
igain[ich]);
659 bool chanLoIsBad =
false;
660 bool chanHiIsBad =
false;
664 chanLoIsBad = statusLo.
isBad();
665 chanHiIsBad = statusHi.
isBad();
669 double pedSimHi(0.), sigmaHi_Hfn1(0.), sigmaHi_Hfn2(0.), sigmaHi_Norm(0.), pedSimLo(0.),
670 sigmaLo_Hfn1(0.), sigmaLo_Hfn2(0.), sigmaLo_Norm(0.);
671 bool good_ch = (over_gain[ich]<9);
674 bool tileNoiseHG(
false),tileNoiseLG(
false);
682 if (pedSimHi == 0.0 && (signal_in_channel[ich] || pmt_id.
is_valid()))
687 if (sigmaHi_Hfn1>0 || sigmaHi_Hfn2) {
688 sigmaHi_Norm = sigmaHi_Hfn1 / (sigmaHi_Hfn1
702 if (pedSimLo == 0.0 && (signal_in_channel[ich] || pmt_id.
is_valid()))
707 if (sigmaLo_Hfn1 > 0 || sigmaLo_Hfn2) {
708 sigmaLo_Norm = sigmaLo_Hfn1 / (sigmaLo_Hfn1
718 RandGaussQ::shootArray(rngEngine,
m_nSamples, Rndm, 0.0, 1.0);
719 RandFlat::shootArray(rngEngine, 1, Rndm_dG, 0.0, 1.0);
721 RandGaussQ::shootArray(rngEngine,
m_nSamples, RndmLo, 0.0, 1.0);
722 RandFlat::shootArray(rngEngine, 1, RndmLo_dG, 0.0, 1.0);
726 std::vector<double>& digitSamplesHi = drawerBufferHi[ich];
727 std::vector<double>& digitSamplesLo = drawerBufferLo[ich];
728 std::vector<double>& digitSamplesHi_DigiHSTruth = (
m_doDigiTruth) ? drawerBufferHi_DigiHSTruth[ich] : emptyBuffer;
729 std::vector<double>& digitSamplesLo_DigiHSTruth = (
m_doDigiTruth) ? drawerBufferLo_DigiHSTruth[ich] : emptyBuffer;
732 <<
" sampHi=" << digitSamplesHi[
m_iTrig]
733 <<
" pedHi=" << pedSimHi
734 <<
" sampLo=" << digitSamplesLo[
m_iTrig]
735 <<
" pedLo=" << pedSimLo);
740 digitsBuffer[js] = digitSamplesHi[js] + pedSimHi;
742 digitsBuffer_DigiHSTruth[js] = digitSamplesHi_DigiHSTruth[js] + pedSimHi;
749 std::unique_ptr<double[]>& CorVec = CorrRndmVec[js];
751 for (
int i = 0;
i < nchMax; ++
i) noiseHi += CorrWeightHi(
i, ich) * CorVec[
i];
752 }
else if (tileNoiseHG) {
754 if (Rndm_dG[0] < sigmaHi_Norm) noiseHi = sigmaHi_Hfn1 * Rndm[js];
755 else noiseHi = sigmaHi_Hfn2 * Rndm[js];
758 if (digitsBuffer[js] + noiseHi >= 0.0) {
759 digitsBuffer[js] += noiseHi;
762 digitsBuffer[js] -= noiseHi;
768 digitsBuffer[js] =
round(digitsBuffer[js]);
773 digitsBufferLo[js] = digitSamplesLo[js] + pedSimLo;
774 if(
m_doDigiTruth) digitsBufferLo_DigiHSTruth[js] = digitSamplesLo_DigiHSTruth[js] + pedSimLo;
779 std::unique_ptr<double[]>& CorVecLo = CorrRndmVecLo[js];
781 for (
int i = 0;
i < nchMax; ++
i) noiseLo += CorrWeightLo(
i, ich) * CorVecLo[
i];
782 }
else if (tileNoiseLG) {
784 if (RndmLo_dG[0] < sigmaLo_Norm) noiseLo = sigmaLo_Hfn1 * RndmLo[js];
785 else noiseLo = sigmaLo_Hfn2 * RndmLo[js];
788 if (digitsBufferLo[js] + noiseLo >= 0.0) {
789 digitsBufferLo[js] += noiseLo;
792 digitsBufferLo[js] -= noiseLo;
797 digitsBufferLo[js] =
round(digitsBufferLo[js]);
798 if(
m_doDigiTruth) digitsBufferLo_DigiHSTruth[js] =
round(digitsBufferLo_DigiHSTruth[js]);
811 digitsBuffer[js] = digitSamplesLo[js] + pedSimLo;
812 if(
m_doDigiTruth) digitsBuffer_DigiHSTruth[js] = digitSamplesLo_DigiHSTruth[js] + pedSimLo;
817 double* CorVec = CorrRndmVec[js].get();
819 for (
int i = 0;
i < nchMax; ++
i) noiseLo += CorrWeightLo(
i, ich) * CorVec[
i];
820 }
else if (tileNoiseLG) {
823 if (Rndm_dG[0] < sigmaLo_Norm) noiseLo = sigmaLo_Hfn1 * Rndm[js];
824 else noiseLo = sigmaLo_Hfn2 * Rndm[js];
827 if (digitsBuffer[js] + noiseLo >= 0.0) {
828 digitsBuffer[js] += noiseLo;
831 digitsBuffer[js] -= noiseLo;
835 if (digitsBuffer[js] >
m_f_ADCmax && good_ch) {
840 digitsBuffer[js] =
round(digitsBuffer[js]);
849 <<
" Switch to low gain Amp(lo)=" << digitsBuffer[
m_iTrig] <<
endmsg;
851 if (sigmaLo_Norm<1.0) {
853 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
" " << sigmaLo_Hfn2 <<
" " << sigmaLo_Norm
854 << ((Rndm_dG[0] < sigmaLo_Norm)?(
" sig1 used"):(
" sig2 used")) <<
endmsg;
857 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
endmsg;
866 if (sigmaHi_Norm<1.0) {
868 << pedSimHi <<
" " << sigmaHi_Hfn1 <<
" " << sigmaHi_Hfn2 <<
" " << sigmaHi_Norm
869 << ((Rndm_dG[0] < sigmaHi_Norm)?(
" sig1 used"):(
" sig2 used")) <<
endmsg;
872 << pedSimHi <<
" " << sigmaHi_Hfn1 <<
endmsg;
876 if (sigmaLo_Norm<1.0) {
878 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
" " << sigmaLo_Hfn2 <<
" " << sigmaLo_Norm
879 << ((RndmLo_dG[0] < sigmaLo_Norm)?(
" sig1 used"):(
" sig2 used")) <<
endmsg;
882 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
endmsg;
897 auto pDigits = std::make_unique<TileDigits>(adc_id, digitsBuffer);
898 ATH_CHECK( digitsContainer->push_back(std::move(pDigits)) );
901 auto digits_DigiHSTruth = std::make_unique<TileDigits>(adc_id, digitsBuffer_DigiHSTruth);
914 auto pDigitsLo = std::make_unique<TileDigits>(adc_id_lo, digitsBufferLo);
915 ATH_CHECK( digitsContainer->push_back(std::move(pDigitsLo)) );
918 auto pDigitsLo_DigiHSTruth = std::make_unique<TileDigits>(adc_id_lo, digitsBufferLo_DigiHSTruth);
919 ATH_CHECK( digitsContainer_DigiHSTruth->
push_back(std::move(pDigitsLo_DigiHSTruth)) );
926 bool isChannelGood =
true;
929 double ampInTime = digitsBuffer[
m_iTrig] - pedSimHi;
931 ampInTime =
round(ampInTime);
934 isChannelGood =
false;
937 isChannelGood =
false;
943 echtot_Acc += ech_tot[ich];
944 echint_Acc += fabs(ech_int[ich]);
963 }
else if (good_ch) {
965 std::fill(digitsBuffer.begin(), digitsBuffer.end(), 0.);
967 std::fill(digitsBuffer_DigiHSTruth.begin(), digitsBuffer_DigiHSTruth.end(), 0.);
984 }
else if (good_ch) {
986 std::fill(digitsBuffer.begin(), digitsBuffer.end(), 0.);
988 std::fill(digitsBuffer_DigiHSTruth.begin(), digitsBuffer_DigiHSTruth.end(), 0.);
995 auto pDigits = std::make_unique<TileDigits>(adc_id, digitsBuffer);
1006 ATH_CHECK( digitsContainer->push_back(std::move(pDigits)) );
1008 auto pDigits_DigiHSTruth = std::make_unique<TileDigits>(adc_id, digitsBuffer_DigiHSTruth);
1013 double pedSim = ((hiGain) ? pedSimHi : pedSimLo);
1014 double ampInTime = digitsBuffer[
m_iTrig] - pedSim;
1016 ampInTime =
round(ampInTime);
1020 <<
" AinT=" << ampInTime
1021 <<
" ped=" << pedSim
1022 <<
" Ech=" << ech_tot[ich]
1023 <<
" EinT=" << ech_int[ich] <<
endmsg;
1025 for (
unsigned int i = 0;
i < digitsBuffer.size(); ++
i)
1030 echtot_Cut += ech_tot[ich];
1031 echint_Cut += ech_int[ich];
1039 double pedSim = ((hiGain) ? pedSimHi : pedSimLo);
1040 double ampInTime = digitsBuffer[
m_iTrig] - pedSim;
1042 ampInTime =
round(ampInTime);
1044 <<
" AinT=" << ampInTime
1045 <<
" ped=" << pedSim
1046 <<
" Ech=" << ech_tot[ich]
1047 <<
" EinT=" << ech_int[ich] <<
endmsg;
1058 <<
" nChH/L=" << nChHiSum <<
"/" << nChLoSum
1059 <<
" nFltH/L=" << nChHiFlt <<
"/" << nChLoFlt
1061 <<
" Ene=" << EneSum
1062 <<
" RChSum=" << RChSum <<
endmsg;
1064 msg(
MSG::DEBUG) <<
" Accepted: nChLo/Hi=" << nChLoAcc <<
"/" << nChHiAcc
1065 <<
" eTot=" << echtot_Acc
1066 <<
" eInT=" << echint_Acc <<
endmsg;
1067 msg(
MSG::DEBUG) <<
" Rejected: nChLo/Hi=" << nChLoCut <<
"/" << nChHiCut
1068 <<
" eTot=" << echtot_Cut
1069 <<
" eInT=" << echint_Cut <<
endmsg;
1080 ATH_CHECK( digits_DigiHSTruth.
record(std::move(digitsContainer_DigiHSTruth)) );
1083 if (filteredContainer) {
1085 ATH_CHECK( filteredDigitsContainer.
record(std::move(filteredContainer)) );
1088 return StatusCode::SUCCESS;
1092 ATH_MSG_INFO(
"TileDigitsMaker finalized successfully");
1094 return StatusCode::SUCCESS;
1098 std::vector<std::vector<double>>& drawerBufferLo,
1099 std::vector<std::vector<double>>& drawerBufferHi,
1100 std::vector<int>&
igain, std::vector<int>& over_gain, std::vector<double>& ech_int,
1101 std::vector<bool> &signal_in_channel,
const TileEMScale* emScale,
1104 constexpr
int nchMax = 48;
1105 std::array<int, nchMax> ntot_ch; ntot_ch.fill(0);
1106 std::array<double, nchMax> ech_tot; ech_tot.fill(0.0);
1119 for (
const TileHit* tileHit : *hitCollection) {
1126 signal_in_channel[ich] =
true;
1128 if (over_gain[ich] > 9) {
1130 int n_hits = tileHit->size();
1132 for (
int ihit = 0; ihit < n_hits; ++ihit) {
1133 e_hit += tileHit->energy(ihit);
1136 ech_tot[ich] += e_hit;
1137 ntot_ch[ich] += n_hits;
1150 hit_calib =
std::round(hit_calib * 1000) / 1000;
1159 std::vector<double>& digitSamplesHi = drawerBufferHi[ich];
1160 std::vector<double>& digitSamplesLo = drawerBufferLo[ich];
1163 int n_hits = tileHit->size();
1164 for (
int ihit = 0; ihit < n_hits; ++ihit) {
1166 double e_hit = tileHit->energy(ihit);
1167 double amp_ch = e_hit * efactorHi;
1168 double amp_ch_lo = e_hit * efactorLo;
1169 double ech_sub = e_hit * hit_calib;
1170 double t_hit = tileHit->time(ihit);
1172 ech_tot[ich] += ech_sub;
1173 if (fabs(t_hit) < 50.0)
1174 ech_int[ich] += ech_sub * mbts_extra_factor;
1191 digitSamplesHi[js] += amp_ch * ampl;
1193 <<
" Pulse index=" <<
k
1194 <<
" Shape wt. =" << ampl
1195 <<
" HIGAIN from COOL");
1200 <<
" Pulse index=" <<
k
1202 <<
" HIGAIN from TileInfo");
1219 digitSamplesLo[js] += amp_ch_lo * ampl;
1221 <<
" Pulse index=" <<
k
1222 <<
" Shape wt. =" << ampl
1223 <<
" LOGAIN from COOL");
1227 <<
" Pulse index=" <<
k
1229 <<
" LOGAIN from TileInfo");
1236 <<
" e_hit=" << e_hit
1237 <<
" t_hit=" << t_hit
1245 return StatusCode::SUCCESS;
1251 std::vector<std::vector<double>>& drawerBufferLo,
1252 std::vector<std::vector<double>>& drawerBufferHi,
1254 std::vector<int>& over_gain,
const TileEMScale* emScale,
1259 ATH_MSG_ERROR (
"Frag IDs for hit collection and digits overlay collection do not match "
1260 << MSG::hex << hitCollection->
identify() <<
" != " << bkgDigitCollection->
identify()
1262 return StatusCode::FAILURE;
1267 for (
const auto* bkgDigit : *bkgDigitCollection) {
1281 std::vector<float> digits = bkgDigit->samples();
1283 int nSamp2 = digits.size();
1284 int goodDigits = nSamp2;
1286 if (goodDigits > 0) {
1287 auto minmax = std::minmax_element(digits.begin(), digits.end());
1288 digmin = *minmax.first;
1289 digmax = *minmax.second;
1298 int badDigits = std::count_if(digits.begin(), digits.end(), [ADCmaxMinusEps](
float dig){
1299 return (dig < 0.01) || (dig > ADCmaxMinusEps);});
1300 goodDigits -= badDigits;
1301 dig = digits.back();
1303 }
else if (goodDigits>0) {
1305 dig = digits.back();
1311 float lastDigit = digits.back();
1314 std::fill(digits.begin() + nSamp2, digits.end(), lastDigit);
1318 std::vector<double>& bufferLG = drawerBufferLo[
channel];
1320 bool isFilledLG =
false;
1322 if (digmax - digmin > 5. && good_ch ) {
1328 std::transform(digits.begin(), digits.end(), bufferLG.begin(), [dig,
ratio](
float digit){return (digit - dig) * ratio;});
1344 }
else if (isFilledLG) {
1352 }
else if (nSamp2 > 0) {
1357 if (digmin != digmax || (dig!=0. && dig!=
m_f_ADCmax)) {
1365 for (
int js = 0; js < nSamp2; ++js)
1372 <<
" samples= 0 0 0 0 0 0 0"
1373 << ((good_ch)?
"":
" BCH") << ((good_dq)?
"":
" BDQ") );
1376 return StatusCode::SUCCESS;