44 #include "GaudiKernel/ThreadLocalContext.h"
49 #include <CLHEP/Random/Randomize.h>
53 #include "TDecompChol.h"
58 using CLHEP::RandGaussQ;
59 using CLHEP::RandFlat;
113 ATH_MSG_DEBUG(
"Initializing pulse shape conditions object");
145 ATH_MSG_DEBUG(
"Pileup and/or noise added by overlaying digits of random events");
164 <<
", tileThresh=" << ((
m_tileThresh) ?
"true" :
"false");
186 ATH_MSG_DEBUG(
"Keep digits from MBTS with original G4 hit energy above "
214 const int nchMax = 48;
217 <<
" nchMax=" << nchMax
223 for (
int dr = 0;
dr < ndrawers; ++
dr) {
228 std::unique_ptr<HWIdentifier[]>& adc_ids =
m_all_ids.back();
236 if (drawerIdx != (
int)idhash) {
238 <<
" hash " << idhash <<
" NOT EQUAL to idx " << drawerIdx);
241 <<
" hash " << idhash <<
endmsg;
244 for (
int ch = 0;
ch < nchMax; ++
ch) {
258 return StatusCode::SUCCESS;
267 CLHEP::HepRandomEngine* rngEngine =
nullptr;
283 const int nchMax = 48;
284 for (
int dr = 0;
dr < ndrawers; ++
dr) {
292 for (
int ch = 0;
ch < nchMax; ++
ch) {
302 <<
" pedHi="<< pedSimHi
303 <<
" pedLo="<< pedSimLo
304 <<
" rmsHi="<< sigmaHi_Hfn1 <<
"," << sigmaHi_Hfn2 <<
"," << sigmaHi_Norm
305 <<
" rmsLo="<< sigmaLo_Hfn1 <<
"," << sigmaLo_Hfn2 <<
"," << sigmaLo_Norm);
338 double echtot_Acc = 0.;
339 double echint_Acc = 0.;
340 double echtot_Cut = 0.;
341 double echint_Cut = 0.;
348 auto digitsContainer = std::make_unique<TileMutableDigitsContainer>(
true,
353 std::unique_ptr<TileMutableDigitsContainer> digitsContainer_DigiHSTruth;
355 digitsContainer_DigiHSTruth = std::make_unique<TileMutableDigitsContainer>(
true,
361 std::unique_ptr<TileMutableDigitsContainer> filteredContainer;
363 filteredContainer = std::make_unique<TileMutableDigitsContainer>(
true,
373 const int nchMax = 48;
374 std::vector<int>
igain(nchMax, -1);
375 std::vector<int> ntot_ch(nchMax, 0);
376 std::vector<double> ech_tot(nchMax, 0.0);
377 std::vector<double> ech_int(nchMax, 0);
378 std::vector<double> ech_int_DigiHSTruth(nchMax, 0);
379 std::vector<int> over_gain(nchMax, -1);
383 std::vector<float> digitsBufferLo(
m_nSamples);
384 std::vector<float> digitsBuffer_DigiHSTruth(
m_nSamples);
385 std::vector<float> digitsBufferLo_DigiHSTruth(
m_nSamples);
387 std::vector<double> emptyBuffer;
388 std::vector<std::vector<double>> drawerBufferHi(nchMax, std::vector<double>(
m_nSamples));
389 std::vector<std::vector<double>> drawerBufferLo(nchMax, std::vector<double>(
m_nSamples));
391 std::vector<std::vector<double>> drawerBufferHi_DigiHSTruth;
392 std::vector<std::vector<double>> drawerBufferLo_DigiHSTruth;
394 drawerBufferHi_DigiHSTruth.resize(nchMax, std::vector<double>(
m_nSamples));
395 drawerBufferLo_DigiHSTruth.resize(nchMax, std::vector<double>(
m_nSamples));
401 Bool_t coherNoiseHi =
false;
402 Bool_t coherNoiseLo =
false;
403 TMatrixD CorrWeightHi;
404 TMatrixD CorrWeightLo;
405 std::vector<std::unique_ptr<double[]>> CorrRndmVec;
406 std::vector<std::unique_ptr<double[]>> CorrRndmVecLo;
418 TileMutableDigitsContainer::const_iterator collItrRndm;
419 TileMutableDigitsContainer::const_iterator lastCollRndm;
420 std::unique_ptr<TileMutableDigitsContainer> backgroundDigitContainer{};
422 backgroundDigitContainer = std::make_unique<TileMutableDigitsContainer>(
true,
425 ATH_CHECK( backgroundDigitContainer->status() );
429 TimedDigitContList digitContList;
434 if (digitContList.size() == 0) {
436 return StatusCode::SUCCESS;
440 for (
const auto* digitCollection : *(iTzeroDigitCont->second)) {
441 for (
const auto*
digit : *digitCollection) {
442 auto pDigits = std::make_unique<TileDigits>(*
digit);
443 ATH_CHECK(backgroundDigitContainer->push_back(std::move(pDigits)));
449 if (tileDigitsContainerHandle.
isValid()) {
450 for (
const auto* digitCollection : *tileDigitsContainerHandle) {
451 for (
const auto*
digit : *digitCollection) {
452 auto pDigits = std::make_unique<TileDigits>(*
digit);
453 ATH_CHECK(backgroundDigitContainer->push_back(std::move(pDigits)));
458 ATH_MSG_ERROR(
"ReadHandle to Background Digits is invalid.");
459 return StatusCode::FAILURE;
463 collItrRndm = backgroundDigitContainer->begin();
464 lastCollRndm = backgroundDigitContainer->end();
484 dqStatus = DQstatusHandle.
get();
491 badChannels = badChannelsHandle.
retrieve();
517 ++collItr_DigiHSTruth;
523 const std::unique_ptr<HWIdentifier[]>& adc_ids =
m_all_ids[idhash];
531 std::fill(over_gain.begin(), over_gain.end(), -1);
536 std::fill(ech_tot.begin(), ech_tot.end(), 0.0);
537 std::fill(ech_int.begin(), ech_int.end(), 0.0);
538 std::fill(ntot_ch.begin(), ntot_ch.end(), 0);
541 std::vector<std::reference_wrapper<std::vector<std::vector<double>>>> drawerBuffers{drawerBufferHi, drawerBufferLo};
543 drawerBuffers.push_back(drawerBufferHi_DigiHSTruth);
544 drawerBuffers.push_back(drawerBufferLo_DigiHSTruth);
546 for (std::vector<std::vector<double>>& drawerBuffer : drawerBuffers) {
547 for (std::vector<double>& digitsBuffer : drawerBuffer) {
548 std::fill(digitsBuffer.begin(), digitsBuffer.end(), 0);
555 igain,
ros,
drawer, drawerIdx, over_gain, *emScale, *sampleNoise, dqStatus, badChannels));
559 std::vector<bool> signal_in_channel(nchMax,
false);
560 std::vector<bool> signal_in_channel_DigiHSTruth(nchMax,
false);
562 igain, over_gain, ech_int, signal_in_channel, *emScale, *samplingFraction, pulse));
565 igain, over_gain, ech_int_DigiHSTruth, signal_in_channel_DigiHSTruth, *emScale, *samplingFraction, pulse));
571 for (
int ich = 0; ich < nchMax; ++ich) {
572 if (
igain[ich] > -1) {
573 std::vector<double>& digitSamplesHi = drawerBufferHi[ich];
574 std::vector<double>& digitSamplesLo = drawerBufferLo[ich];
576 <<
" nhit=" << ntot_ch[ich]
577 <<
" e_ch=" << ech_tot[ich]
578 <<
" AinTHi=" << digitSamplesHi[
m_iTrig]
602 <<
" with " << nchMax <<
" channels and "
621 double* RndmVec = CorrRndmVec[
k].get();
622 RandGaussQ::shootArray(rngEngine, nchMax, RndmVec, 0.0, 1.0);
627 double * RndmVecLo = CorrRndmVecLo[
k].get();
628 RandGaussQ::shootArray(rngEngine, nchMax, RndmVecLo, 0.0, 1.0);
635 for (
int ich = 0; ich < nchMax; ++ich) {
646 <<
" PMT " << (pmt_id.
is_valid() ?
m_tileID->
to_string(pmt_id,-1) : (signal_in_channel[ich] ?
"fake gap" :
"not connected"))
647 <<
" gain=" <<
igain[ich]);
656 bool chanLoIsBad =
false;
657 bool chanHiIsBad =
false;
661 chanLoIsBad = statusLo.
isBad();
662 chanHiIsBad = statusHi.
isBad();
666 double pedSimHi(0.), sigmaHi_Hfn1(0.), sigmaHi_Hfn2(0.), sigmaHi_Norm(0.), pedSimLo(0.),
667 sigmaLo_Hfn1(0.), sigmaLo_Hfn2(0.), sigmaLo_Norm(0.);
668 bool good_ch = (over_gain[ich]<9);
671 bool tileNoiseHG(
false),tileNoiseLG(
false);
679 if (pedSimHi == 0.0 && (signal_in_channel[ich] || pmt_id.
is_valid()))
684 if (sigmaHi_Hfn1>0 || sigmaHi_Hfn2) {
685 sigmaHi_Norm = sigmaHi_Hfn1 / (sigmaHi_Hfn1
699 if (pedSimLo == 0.0 && (signal_in_channel[ich] || pmt_id.
is_valid()))
704 if (sigmaLo_Hfn1 > 0 || sigmaLo_Hfn2) {
705 sigmaLo_Norm = sigmaLo_Hfn1 / (sigmaLo_Hfn1
715 RandGaussQ::shootArray(rngEngine,
m_nSamples, Rndm, 0.0, 1.0);
716 RandFlat::shootArray(rngEngine, 1, Rndm_dG, 0.0, 1.0);
718 RandGaussQ::shootArray(rngEngine,
m_nSamples, RndmLo, 0.0, 1.0);
719 RandFlat::shootArray(rngEngine, 1, RndmLo_dG, 0.0, 1.0);
723 std::vector<double>& digitSamplesHi = drawerBufferHi[ich];
724 std::vector<double>& digitSamplesLo = drawerBufferLo[ich];
725 std::vector<double>& digitSamplesHi_DigiHSTruth = (
m_doDigiTruth) ? drawerBufferHi_DigiHSTruth[ich] : emptyBuffer;
726 std::vector<double>& digitSamplesLo_DigiHSTruth = (
m_doDigiTruth) ? drawerBufferLo_DigiHSTruth[ich] : emptyBuffer;
729 <<
" sampHi=" << digitSamplesHi[
m_iTrig]
730 <<
" pedHi=" << pedSimHi
731 <<
" sampLo=" << digitSamplesLo[
m_iTrig]
732 <<
" pedLo=" << pedSimLo);
737 digitsBuffer[js] = digitSamplesHi[js] + pedSimHi;
739 digitsBuffer_DigiHSTruth[js] = digitSamplesHi_DigiHSTruth[js] + pedSimHi;
746 std::unique_ptr<double[]>& CorVec = CorrRndmVec[js];
748 for (
int i = 0;
i < nchMax; ++
i) noiseHi += CorrWeightHi(
i, ich) * CorVec[
i];
749 }
else if (tileNoiseHG) {
751 if (Rndm_dG[0] < sigmaHi_Norm) noiseHi = sigmaHi_Hfn1 * Rndm[js];
752 else noiseHi = sigmaHi_Hfn2 * Rndm[js];
755 if (digitsBuffer[js] + noiseHi >= 0.0) {
756 digitsBuffer[js] += noiseHi;
759 digitsBuffer[js] -= noiseHi;
765 digitsBuffer[js] =
round(digitsBuffer[js]);
770 digitsBufferLo[js] = digitSamplesLo[js] + pedSimLo;
771 if(
m_doDigiTruth) digitsBufferLo_DigiHSTruth[js] = digitSamplesLo_DigiHSTruth[js] + pedSimLo;
776 std::unique_ptr<double[]>& CorVecLo = CorrRndmVecLo[js];
778 for (
int i = 0;
i < nchMax; ++
i) noiseLo += CorrWeightLo(
i, ich) * CorVecLo[
i];
779 }
else if (tileNoiseLG) {
781 if (RndmLo_dG[0] < sigmaLo_Norm) noiseLo = sigmaLo_Hfn1 * RndmLo[js];
782 else noiseLo = sigmaLo_Hfn2 * RndmLo[js];
785 if (digitsBufferLo[js] + noiseLo >= 0.0) {
786 digitsBufferLo[js] += noiseLo;
789 digitsBufferLo[js] -= noiseLo;
794 digitsBufferLo[js] =
round(digitsBufferLo[js]);
795 if(
m_doDigiTruth) digitsBufferLo_DigiHSTruth[js] =
round(digitsBufferLo_DigiHSTruth[js]);
808 digitsBuffer[js] = digitSamplesLo[js] + pedSimLo;
809 if(
m_doDigiTruth) digitsBuffer_DigiHSTruth[js] = digitSamplesLo_DigiHSTruth[js] + pedSimLo;
814 double* CorVec = CorrRndmVec[js].get();
816 for (
int i = 0;
i < nchMax; ++
i) noiseLo += CorrWeightLo(
i, ich) * CorVec[
i];
817 }
else if (tileNoiseLG) {
820 if (Rndm_dG[0] < sigmaLo_Norm) noiseLo = sigmaLo_Hfn1 * Rndm[js];
821 else noiseLo = sigmaLo_Hfn2 * Rndm[js];
824 if (digitsBuffer[js] + noiseLo >= 0.0) {
825 digitsBuffer[js] += noiseLo;
828 digitsBuffer[js] -= noiseLo;
832 if (digitsBuffer[js] >
m_f_ADCmax && good_ch) {
837 digitsBuffer[js] =
round(digitsBuffer[js]);
846 <<
" Switch to low gain Amp(lo)=" << digitsBuffer[
m_iTrig] <<
endmsg;
848 if (sigmaLo_Norm<1.0) {
850 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
" " << sigmaLo_Hfn2 <<
" " << sigmaLo_Norm
851 << ((Rndm_dG[0] < sigmaLo_Norm)?(
" sig1 used"):(
" sig2 used")) <<
endmsg;
854 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
endmsg;
863 if (sigmaHi_Norm<1.0) {
865 << pedSimHi <<
" " << sigmaHi_Hfn1 <<
" " << sigmaHi_Hfn2 <<
" " << sigmaHi_Norm
866 << ((Rndm_dG[0] < sigmaHi_Norm)?(
" sig1 used"):(
" sig2 used")) <<
endmsg;
869 << pedSimHi <<
" " << sigmaHi_Hfn1 <<
endmsg;
873 if (sigmaLo_Norm<1.0) {
875 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
" " << sigmaLo_Hfn2 <<
" " << sigmaLo_Norm
876 << ((RndmLo_dG[0] < sigmaLo_Norm)?(
" sig1 used"):(
" sig2 used")) <<
endmsg;
879 << pedSimLo <<
" " << sigmaLo_Hfn1 <<
endmsg;
894 auto pDigits = std::make_unique<TileDigits>(adc_id, digitsBuffer);
895 ATH_CHECK( digitsContainer->push_back(std::move(pDigits)) );
898 auto digits_DigiHSTruth = std::make_unique<TileDigits>(adc_id, digitsBuffer_DigiHSTruth);
911 auto pDigitsLo = std::make_unique<TileDigits>(adc_id_lo, digitsBufferLo);
912 ATH_CHECK( digitsContainer->push_back(std::move(pDigitsLo)) );
915 auto pDigitsLo_DigiHSTruth = std::make_unique<TileDigits>(adc_id_lo, digitsBufferLo_DigiHSTruth);
916 ATH_CHECK( digitsContainer_DigiHSTruth->
push_back(std::move(pDigitsLo_DigiHSTruth)) );
923 bool isChannelGood =
true;
926 double ampInTime = digitsBuffer[
m_iTrig] - pedSimHi;
928 ampInTime =
round(ampInTime);
931 isChannelGood =
false;
934 isChannelGood =
false;
940 echtot_Acc += ech_tot[ich];
941 echint_Acc += fabs(ech_int[ich]);
960 }
else if (good_ch) {
962 std::fill(digitsBuffer.begin(), digitsBuffer.end(), 0.);
964 std::fill(digitsBuffer_DigiHSTruth.begin(), digitsBuffer_DigiHSTruth.end(), 0.);
981 }
else if (good_ch) {
983 std::fill(digitsBuffer.begin(), digitsBuffer.end(), 0.);
985 std::fill(digitsBuffer_DigiHSTruth.begin(), digitsBuffer_DigiHSTruth.end(), 0.);
992 auto pDigits = std::make_unique<TileDigits>(adc_id, digitsBuffer);
1003 ATH_CHECK( digitsContainer->push_back(std::move(pDigits)) );
1005 auto pDigits_DigiHSTruth = std::make_unique<TileDigits>(adc_id, digitsBuffer_DigiHSTruth);
1010 double pedSim = ((hiGain) ? pedSimHi : pedSimLo);
1011 double ampInTime = digitsBuffer[
m_iTrig] - pedSim;
1013 ampInTime =
round(ampInTime);
1017 <<
" AinT=" << ampInTime
1018 <<
" ped=" << pedSim
1019 <<
" Ech=" << ech_tot[ich]
1020 <<
" EinT=" << ech_int[ich] <<
endmsg;
1022 for (
unsigned int i = 0;
i < digitsBuffer.size(); ++
i)
1027 echtot_Cut += ech_tot[ich];
1028 echint_Cut += ech_int[ich];
1036 double pedSim = ((hiGain) ? pedSimHi : pedSimLo);
1037 double ampInTime = digitsBuffer[
m_iTrig] - pedSim;
1039 ampInTime =
round(ampInTime);
1041 <<
" AinT=" << ampInTime
1042 <<
" ped=" << pedSim
1043 <<
" Ech=" << ech_tot[ich]
1044 <<
" EinT=" << ech_int[ich] <<
endmsg;
1055 <<
" nChH/L=" << nChHiSum <<
"/" << nChLoSum
1056 <<
" nFltH/L=" << nChHiFlt <<
"/" << nChLoFlt
1058 <<
" Ene=" << EneSum
1059 <<
" RChSum=" << RChSum <<
endmsg;
1061 msg(
MSG::DEBUG) <<
" Accepted: nChLo/Hi=" << nChLoAcc <<
"/" << nChHiAcc
1062 <<
" eTot=" << echtot_Acc
1063 <<
" eInT=" << echint_Acc <<
endmsg;
1064 msg(
MSG::DEBUG) <<
" Rejected: nChLo/Hi=" << nChLoCut <<
"/" << nChHiCut
1065 <<
" eTot=" << echtot_Cut
1066 <<
" eInT=" << echint_Cut <<
endmsg;
1077 ATH_CHECK( digits_DigiHSTruth.
record(std::move(digitsContainer_DigiHSTruth)) );
1080 if (filteredContainer) {
1082 ATH_CHECK( filteredDigitsContainer.
record(std::move(filteredContainer)) );
1085 return StatusCode::SUCCESS;
1091 return StatusCode::SUCCESS;
1095 std::vector<std::vector<double>>& drawerBufferLo,
1096 std::vector<std::vector<double>>& drawerBufferHi,
1097 std::vector<int>&
igain, std::vector<int>& over_gain, std::vector<double>& ech_int,
1098 std::vector<bool> &signal_in_channel,
const TileEMScale* emScale,
1101 constexpr
int nchMax = 48;
1102 std::array<int, nchMax> ntot_ch; ntot_ch.fill(0);
1103 std::array<double, nchMax> ech_tot; ech_tot.fill(0.0);
1116 for (
const TileHit* tileHit : *hitCollection) {
1123 signal_in_channel[ich] =
true;
1125 if (over_gain[ich] > 9) {
1127 int n_hits = tileHit->size();
1129 for (
int ihit = 0; ihit < n_hits; ++ihit) {
1130 e_hit += tileHit->energy(ihit);
1133 ech_tot[ich] += e_hit;
1134 ntot_ch[ich] += n_hits;
1147 hit_calib =
std::round(hit_calib * 1000) / 1000;
1156 std::vector<double>& digitSamplesHi = drawerBufferHi[ich];
1157 std::vector<double>& digitSamplesLo = drawerBufferLo[ich];
1160 int n_hits = tileHit->size();
1161 for (
int ihit = 0; ihit < n_hits; ++ihit) {
1163 double e_hit = tileHit->energy(ihit);
1164 double amp_ch = e_hit * efactorHi;
1165 double amp_ch_lo = e_hit * efactorLo;
1166 double ech_sub = e_hit * hit_calib;
1167 double t_hit = tileHit->time(ihit);
1169 ech_tot[ich] += ech_sub;
1170 if (fabs(t_hit) < 50.0)
1171 ech_int[ich] += ech_sub * mbts_extra_factor;
1188 digitSamplesHi[js] += amp_ch * ampl;
1190 <<
" Pulse index=" <<
k
1191 <<
" Shape wt. =" << ampl
1192 <<
" HIGAIN from COOL");
1197 <<
" Pulse index=" <<
k
1199 <<
" HIGAIN from TileInfo");
1216 digitSamplesLo[js] += amp_ch_lo * ampl;
1218 <<
" Pulse index=" <<
k
1219 <<
" Shape wt. =" << ampl
1220 <<
" LOGAIN from COOL");
1224 <<
" Pulse index=" <<
k
1226 <<
" LOGAIN from TileInfo");
1233 <<
" e_hit=" << e_hit
1234 <<
" t_hit=" << t_hit
1242 return StatusCode::SUCCESS;
1248 std::vector<std::vector<double>>& drawerBufferLo,
1249 std::vector<std::vector<double>>& drawerBufferHi,
1251 std::vector<int>& over_gain,
const TileEMScale* emScale,
1256 ATH_MSG_ERROR (
"Frag IDs for hit collection and digits overlay collection do not match "
1257 << MSG::hex << hitCollection->
identify() <<
" != " << bkgDigitCollection->
identify()
1259 return StatusCode::FAILURE;
1264 for (
const auto* bkgDigit : *bkgDigitCollection) {
1278 std::vector<float> digits = bkgDigit->samples();
1280 int nSamp2 = digits.size();
1281 int goodDigits = nSamp2;
1283 if (goodDigits > 0) {
1284 auto minmax = std::minmax_element(digits.begin(), digits.end());
1285 digmin = *minmax.first;
1286 digmax = *minmax.second;
1295 int badDigits = std::count_if(digits.begin(), digits.end(), [ADCmaxMinusEps](
float dig){
1296 return (dig < 0.01) || (dig > ADCmaxMinusEps);});
1297 goodDigits -= badDigits;
1298 dig = digits.back();
1300 }
else if (goodDigits>0) {
1302 dig = digits.back();
1308 float lastDigit = digits.back();
1311 std::fill(digits.begin() + nSamp2, digits.end(), lastDigit);
1315 std::vector<double>& bufferLG = drawerBufferLo[
channel];
1317 bool isFilledLG =
false;
1319 if (digmax - digmin > 5. && good_ch ) {
1325 std::transform(digits.begin(), digits.end(), bufferLG.begin(), [dig,
ratio](
float digit){return (digit - dig) * ratio;});
1341 }
else if (isFilledLG) {
1349 }
else if (nSamp2 > 0) {
1354 if (digmin != digmax || (dig!=0. && dig!=
m_f_ADCmax)) {
1362 for (
int js = 0; js < nSamp2; ++js)
1369 <<
" samples= 0 0 0 0 0 0 0"
1370 << ((good_ch)?
"":
" BCH") << ((good_dq)?
"":
" BDQ") );
1373 return StatusCode::SUCCESS;