18 #include "GaudiKernel/SystemOfUnits.h"
19 #include "GaudiKernel/PhysicalConstants.h"
21 #include "GeoModelHelpers/TransformToStringConverter.h"
41 #include "GeoModelHelpers/throwExcept.h"
44 #include "CLHEP/Random/RandExponential.h"
45 #include "CLHEP/Random/RandFlat.h"
46 #include "CLHEP/Random/RandGaussZiggurat.h"
62 constexpr
int N_Charge = 12;
63 constexpr
int N_Velocity = 15;
64 constexpr std::array<double, N_Charge> Charge{0.1, 0.2, 0.3, 0.33, 0.4, 0.5, 0.6, 0.66, 0.7, 0.8, 0.9, 1.0};
65 constexpr std::array<double, N_Velocity> Velocity{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 10.0, 100.0, 1000.0};
66 constexpr
double Eff_garfield[N_Charge][N_Velocity] = {
67 {0.8648, 0.3476, 0.1407, 0.0618, 0.0368, 0.0234, 0.0150, 0.0120, 0.0096, 0.0079, 0.0038, 0.0041, 0.0035, 0.0049, 0.0054},
68 {0.9999, 0.9238, 0.6716, 0.4579, 0.3115, 0.2238, 0.1727, 0.1365, 0.1098, 0.0968, 0.0493, 0.0451, 0.0528, 0.0694, 0.0708},
69 {1.0000, 0.9978, 0.9517, 0.8226, 0.6750, 0.5611, 0.4674, 0.3913, 0.3458, 0.3086, 0.1818, 0.1677, 0.1805, 0.2307, 0.2421},
70 {1.0000, 0.9994, 0.9758, 0.8918, 0.7670, 0.6537, 0.5533, 0.4856, 0.4192, 0.3852, 0.2333, 0.2186, 0.2479, 0.2957, 0.2996},
71 {1.0000, 1.0000, 0.9972, 0.9699, 0.9022, 0.8200, 0.7417, 0.6660, 0.6094, 0.5622, 0.3846, 0.3617, 0.3847, 0.4578, 0.4583},
72 {1.0000, 1.0000, 0.9998, 0.9956, 0.9754, 0.9479, 0.9031, 0.8604, 0.8126, 0.7716, 0.5827, 0.5545, 0.5865, 0.6834, 0.6706},
73 {1.0000, 1.0000, 1.0000, 0.9997, 0.9968, 0.9876, 0.9689, 0.9464, 0.9221, 0.8967, 0.7634, 0.7385, 0.7615, 0.8250, 0.8309},
74 {1.0000, 1.0000, 1.0000, 1.0000, 0.9995, 0.9952, 0.9866, 0.9765, 0.9552, 0.9427, 0.8373, 0.8127, 0.8412, 0.8899, 0.8891},
75 {1.0000, 1.0000, 1.0000, 1.0000, 0.9995, 0.9981, 0.9918, 0.9803, 0.9754, 0.9602, 0.8730, 0.8564, 0.8746, 0.9178, 0.9261},
76 {1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 0.9993, 0.9990, 0.9951, 0.9935, 0.9886, 0.9419, 0.9277, 0.9422, 0.9686, 0.9700},
77 {1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 0.9998, 0.9996, 0.9980, 0.9966, 0.9786, 0.9718, 0.9748, 0.9875, 0.9882},
78 {1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 0.9998, 1.0000, 0.9991, 0.9988, 0.9913, 0.9872, 0.9917, 0.9970, 0.9964}};
80 validIndex(
int idx,
int arraySize){
81 return (
idx>=0) and (
idx<arraySize);
87 constexpr
double SIG_VEL = 4.8;
138 return StatusCode::FAILURE;
155 ATH_CHECK(service(
"RDBAccessSvc", rdbAccess));
160 std::string configVal =
"";
162 ATH_CHECK(service(
"GeoModelSvc", geoModel));
167 if (atlasCommonRec->size() == 0) {
170 configVal = (*atlasCommonRec)[0]->getString(
"CONFIG");
171 ATH_MSG_INFO(
"From DD Database, Configuration is " << configVal);
172 if (configVal ==
"RUN1") {
174 }
else if (configVal ==
"RUN2") {
176 }
else if (configVal ==
"RUN3") {
178 }
else if (configVal ==
"RUN4") {
182 ATH_MSG_FATAL(
"Unexpected value for geometry config read from the database: " << configVal);
183 return StatusCode::FAILURE;
190 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN1 or MuonGeometry = R.06");
192 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN2 or MuonGeometry = R.07");
193 else if (
run == Run3)
194 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN3 or MuonGeometry = R.09");
195 else if (
run == Run4)
196 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN4 or MuonGeometry = R.10");
209 if (configVal ==
"RUN1") {
228 ATH_MSG_INFO(
"Run3/4: configuration parameter not from COOL");
235 ATH_MSG_INFO(
"RPC Run1/2/3-dependent configuration is enforced");
237 ATH_MSG_WARNING(
"Run1/2/3-dependent configuration is bypassed; be careful with option settings");
247 ATH_MSG_DEBUG(
"Ready to read parameters for cluster simulation from file");
268 return StatusCode::SUCCESS;
271 template <
class CondType>
274 const CondType* & condPtr)
const {
277 ATH_MSG_DEBUG(
"No key has been configured for object "<<
typeid(CondType).
name()<<
". Clear pointer");
279 return StatusCode::SUCCESS;
282 if (!readHandle.isValid()){
284 return StatusCode::FAILURE;
286 condPtr = readHandle.cptr();
287 return StatusCode::SUCCESS;
296 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>();
299 return StatusCode::SUCCESS;
307 TimedHitCollList hitCollList;
310 hitCollList.empty()) {
312 return StatusCode::FAILURE;
321 for (; iColl != endColl; ++iColl) {
325 ATH_MSG_DEBUG(
"RPCSimHitCollection found with " << hitCollPtr->
size() <<
" hits");
328 m_thpcRPC->insert(timeIndex, hitCollPtr);
332 return StatusCode::SUCCESS;
349 if (!hitCollection.
isValid()) {
350 ATH_MSG_ERROR(
"Could not get RPCSimHitCollection container " << hitCollection.
name() <<
" from store "
351 << hitCollection.
store());
352 return StatusCode::FAILURE;
356 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>(1);
358 ATH_MSG_DEBUG(
"RPCSimHitCollection found with " << hitCollection->
size() <<
" hits");
360 return StatusCode::SUCCESS;
363 TimedHitCollList hitCollList;
367 return StatusCode::FAILURE;
369 if (hitCollList.empty()) {
371 return StatusCode::FAILURE;
377 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>();
381 while (iColl != endColl) {
383 m_thpcRPC->insert(iColl->first, p_collection);
388 return StatusCode::SUCCESS;
403 ATH_CHECK(sdoContainer.
record(std::make_unique<MuonSimDataCollection>()));
413 for (
size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
414 if (collections[coll_hash]) {
440 ATH_CHECK(sdoContainer.
record(std::make_unique<MuonSimDataCollection>()));
449 if (StatusCode::FAILURE ==
status) {
457 for (
size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
458 if (collections[coll_hash]) {
472 CLHEP::HepRandomEngine* rndmEngine = rngWrapper->
getEngine(ctx);
478 std::unique_ptr<RPCSimHitCollection> inputSimHitColl{std::make_unique<RPCSimHitCollection>(
"RPC_Hits")};
488 return StatusCode::FAILURE;
491 struct SimDataContent {
493 std::vector<MuonSimData::Deposit> deposits;
501 std::map<Identifier, SimDataContent> channelSimDataMap;
512 const int idHit = hit.
RPCid();
514 const double globalHitTime{
hitTime(phit)};
518 const double bunchTime{globalHitTime - hit.
globalTime()};
520 ATH_MSG_DEBUG(
"Global time " << globalHitTime <<
" G4 time " << G4Time <<
" Bunch time " << bunchTime);
523 ATH_MSG_VERBOSE(
"Validation: globalHitTime, G4Time, BCtime = " << globalHitTime <<
" " << G4Time <<
" " << bunchTime);
524 inputSimHitColl->Emplace(idHit, globalHitTime, hit.
localPosition(),
564 bool isValidEta{
false}, isValidPhi{
false};
567 if (!isValidEta || !isValidPhi) {
570 <<
" doubletR " <<
doubletR <<
" doubletZ " << doubletZ <<
" doubletPhi " <<
doubletPhi <<
" gasGap "
579 const double corrtimejitter = tmp_CorrJitter > 0.01 ?
580 CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0., tmp_CorrJitter) : 0.;
588 Amg::intersect<3>(hit.
localPosition(), hitDir, Amg::Vector3D::UnitX(), 0).value_or(0) * hitDir;
590 std::array<int, 3> pcseta =
physicalClusterSize(ctx, reEle, idpaneleta, gapCentre, rndmEngine);
591 ATH_MSG_VERBOSE(
"Simulated cluster on eta panel: size/first/last= " << pcseta[0] <<
"/" << pcseta[1] <<
"/" << pcseta[2]);
592 std::array<int, 3> pcsphi =
physicalClusterSize(ctx, reEle, idpanelphi, gapCentre, rndmEngine);
593 ATH_MSG_VERBOSE(
"Simulated cluster on phi panel: size/first/last= " << pcsphi[0] <<
"/" << pcsphi[1] <<
"/" << pcsphi[2]);
602 const auto [etaStripOn, phiStripOn] =
detectionEfficiency(ctx, idpaneleta, idpanelphi, rndmEngine, particleLink);
603 ATH_MSG_DEBUG(
"SetPhiOn " << phiStripOn <<
" SetEtaOn " << etaStripOn);
605 for (
bool imeasphi : {
false,
true}) {
606 if (!imeasphi && (!etaStripOn || !isValidEta))
continue;
607 if (imeasphi && (!phiStripOn || !isValidPhi))
continue;
611 const Identifier& atlasId = !imeasphi ? atlasRpcIdeta : atlasRpcIdphi;
612 std::array<int, 3>
pcs{!imeasphi ? pcseta : pcsphi};
615 <<
" doubletR " <<
doubletR <<
" doubletZ " << doubletZ <<
" doubletPhi " <<
doubletPhi
616 <<
" gasGap " <<
gasGap <<
" measphi " << imeasphi);
643 double tns = G4Time + proptime + corrtimejitter;
644 ATH_MSG_VERBOSE(
"TOF+propagation time " << tns <<
" /s where proptime " << proptime <<
"/s");
646 double time = tns + bunchTime;
652 double*
b =
reinterpret_cast<double*
>(&packedMCword);
664 if (channelSimDataMap.find(atlasId) == channelSimDataMap.end()) {
665 SimDataContent&
content = channelSimDataMap[atlasId];
667 content.deposits.push_back(deposit);
683 for (
int clus =
pcs[1]; clus <=
pcs[2]; ++clus) {
688 <<
" "<<
doubletPhi<<
" "<<
gasGap <<
" "<< imeasphi<<
" "<< clus<<
" is invalid");
694 ATH_MSG_WARNING(
"Temporary skipping creation of RPC digit for stationName="
696 <<
", doubletZ=" << doubletZ <<
", doubletPhi=" <<
doubletPhi <<
", gasGap=" <<
gasGap
697 <<
", measuresPhi=" << imeasphi <<
", strip=" << clus <<
", cf. ATLASRECTS-6124");
698 return StatusCode::SUCCESS;
702 return StatusCode::FAILURE;
711 std::vector<MuonSimData::Deposit> newdeps;
712 newdeps.push_back(deposit);
722 for (
auto it = channelSimDataMap.begin();
it != channelSimDataMap.end(); ++
it) {
726 auto insertResult = sdoContainer->insert(std::make_pair(
it->first,
simData));
727 if (!insertResult.second)
728 ATH_MSG_WARNING(
"Attention: this sdo is not recorded, since the identifier already exists in the sdoContainer map");
741 const Identifier theId = (*map_iter).first;
744 const std::vector<MuonSimData::Deposit> theDeps = (*map_iter).second;
748 std::multimap<double, MuonSimData::Deposit>
times;
751 for (
unsigned int k = 0;
k < theDeps.size();
k++) {
752 double time = theDeps[
k].second.secondEntry();
753 times.insert(std::multimap<double, MuonSimData::Deposit>::value_type(
time, theDeps[
k]));
763 double last_time = -10000;
764 for (; map_dep_iter !=
times.end(); ++map_dep_iter) {
765 double currTime = (*map_dep_iter).first;
771 if (sdoContainer->find(theId) != sdoContainer->end())
773 std::map<Identifier, MuonSimData>::const_iterator
it = sdoContainer->find(theId);
774 std::vector<MuonSimData::Deposit> deps = ((*it).second).getdeposits();
775 deps.push_back((*map_dep_iter).second);
778 std::vector<MuonSimData::Deposit> deposits;
779 deposits.push_back((*map_dep_iter).second);
781 sdoContainer->insert(std::make_pair(theId,
MuonSimData(deposits, 0)));
782 if (!insertResult.second)
784 "Attention TEMP: this sdo is not recorded, since the identifier already exists in the sdoContainer map");
788 if (std::abs(currTime - last_time) > (
m_deadTime)) {
789 ATH_MSG_DEBUG(
"deposit with time " << currTime <<
" is distant enough from previous (if any) hit on teh same strip");
790 last_time = (*map_dep_iter).first;
793 double uncorrjitter = 0;
796 if (tmp_UncorrJitter > 0.01) uncorrjitter = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0., tmp_UncorrJitter);
806 double newDigit_time = currTime + uncorrjitter +
m_rpc_time_shift -
tp - propTimeFromStripCenter;
808 double digi_ToT = -1.;
811 ATH_MSG_VERBOSE(
"last_time=currTime " << last_time <<
" jitter " << uncorrjitter <<
" TOFcorrection " <<
tp <<
" shift "
815 bool outsideDigitizationWindow =
outsideWindow(newDigit_time);
816 if (outsideDigitizationWindow) {
817 ATH_MSG_VERBOSE(
"hit outside digitization window - do not produce digits");
826 last_time = (*map_dep_iter).first;
828 std::unique_ptr<RpcDigit> newDigit = std::make_unique<RpcDigit>(theId, newDigit_time, digi_ToT,
false);
833 IdentifierHash coll_hash;
835 ATH_MSG_ERROR(
"Unable to get RPC hash id from RPC Digit collection "
836 <<
"context begin_index = " << rpcContext.
begin_index()
837 <<
" context end_index = " << rpcContext.
end_index() <<
" the identifier is ");
845 if (coll_hash >= collections.size()) {
846 collections.resize (coll_hash+1);
848 digitCollection = collections[coll_hash].
get();
849 if (!digitCollection) {
850 collections[coll_hash] = std::make_unique<RpcDigitCollection>(elemId, coll_hash);
851 digitCollection = collections[coll_hash].
get();
853 digitCollection->
push_back(std::move(newDigit));
857 if (sdoContainer->find(theId) != sdoContainer->end()) {
858 std::map<Identifier, MuonSimData>::const_iterator
it = sdoContainer->find(theId);
859 std::vector<MuonSimData::Deposit> deps = ((*it).second).getdeposits();
860 deps.push_back((*map_dep_iter).second);
862 std::vector<MuonSimData::Deposit> deposits;
863 deposits.push_back((*map_dep_iter).second);
865 sdoContainer->insert(std::make_pair(theId,
MuonSimData(deposits, 0)));
866 if (!insertResult.second)
868 "Attention: this sdo is not recorded, since teh identifier already exists in the sdoContainer map");
873 ATH_MSG_DEBUG(
"discarding digit due to dead time: " << (*map_dep_iter).first <<
" " << last_time);
882 ATH_CHECK(validHandle.record(std::move(inputSimHitColl)));
885 return StatusCode::SUCCESS;
888 const Identifier& layerId)
const {
911 const Identifier&
id,
913 CLHEP::HepRandomEngine* rndmEngine)
const {
916 std::array<int, 3>
result{};
922 const double pitch= ele->
StripPitch(measuresPhi);
925 const int nstrip = ele->
stripNumber(position.block<2,1>(0,0),
id);
926 const int numStrips = ele->
Nstrips(measuresPhi);
931 if (nstrip < 1 || nstrip > numStrips) {
932 return make_array<int, 3>(-1);
935 float xstripnorm = (locStripPos -position).
x() / pitch ;
948 std::array<int, 3>&&
pcs,
949 const Identifier&
id)
const {
956 }
else if (
pcs[0] == 2) {
958 }
else if (
pcs[0] > 2) {
960 if (fmod(
pcs[0], 2) == 0)
pcs[1] =
pcs[1] + 1;
962 }
else if (
pcs[0] < -2) {
969 pcs[1] = std::clamp(
pcs[1], 1, nstrips);
970 pcs[2] = std::clamp(
pcs[2], 1, nstrips);
979 const Identifier&
id,
990 return std::abs(
distance * SIG_VEL * 1.
e-3);
997 ATH_MSG_WARNING(
"A poblem: packing a propagation time <0 " << proptime <<
" redefine it as 0");
1000 long long int new_proptime =
int(proptime * 10) & 0xff;
1006 long long int new_bctime =
int((bctime + 300.) * 10.) & 0xffff;
1011 long long int new_posy =
int((posy + 1500.) * 10.) & 0xffff;
1016 long long int new_posz =
int((posz + 1500.) * 10.) & 0xffff;
1018 return (new_proptime + (new_bctime << 8) + (new_posy << 24) + (new_posz << 40));
1024 using Repacker =
union
1032 MCTruth.dWord = theWord;
1033 proptime = ((MCTruth.iWord) & 0x00000000000000ffLL) / 10.;
1034 bctime = (((MCTruth.iWord) & 0x0000000000ffff00LL) >> 8) / 10.;
1035 posy = (((MCTruth.iWord) & 0x000000ffff000000LL) >> 24) / 10.;
1036 posz = (((MCTruth.iWord) & 0x00ffff0000000000LL) >> 40) / 10.;
1039 bctime = bctime - 300.;
1040 posy = posy - 1500.;
1041 posz = posz - 1500.;
1048 std::string RpctimeSchema =
"";
1049 std::stringstream RpctimeShift;
1053 RpctimeSchema =
"Datalike_TOFoff_TimeShift" + RpctimeShift.str() +
"nsec";
1055 RpctimeSchema =
"G4like_TOFon_TimeShift" + RpctimeShift.str() +
"nsec";
1060 if (
sc.isFailure()) {
1067 return StatusCode::SUCCESS;
1073 const Identifier& IdEta,
1074 const Identifier& IdPhi,
1075 CLHEP::HepRandomEngine* rndmEngine,
1080 ATH_MSG_DEBUG(
"RpcDigitizationTool::in DetectionEfficiency");
1088 float maxGeomEff{0.99}, PhiAndEtaEff{0.99}, OnlyEtaEff{0.f}, OnlyPhiEff{0.f};
1097 return std::make_pair(
false,
false);
1102 return std::make_pair(
true,
true);
1104 bool etaStripOn{
true}, phiStripOn{
true};
1145 ATH_MSG_DEBUG(
"Efficiencies and cluster size + dead strips will be extracted from COOL");
1147 double FracDeadStripEta{0.}, FracDeadStripPhi{0.};
1148 double EtaPanelEfficiency{1.}, PhiPanelEfficiency{1.}, GapEfficiency{1.};
1149 int RPC_ProjectedTracksEta = 0;
1151 std::optional<double> fracDeadStripEtaFromCOOL = readCdo->getFracDeadStrip(IdEta);
1152 std::optional<double> fracDeadStripPhiFromCOOL = readCdo->getFracDeadStrip(IdPhi);
1154 bool noEntryInDb = !fracDeadStripEtaFromCOOL || !fracDeadStripPhiFromCOOL;
1156 FracDeadStripEta = fracDeadStripEtaFromCOOL.value_or(0.);
1157 FracDeadStripPhi = fracDeadStripPhiFromCOOL.value_or(0.);
1158 RPC_ProjectedTracksEta = readCdo->getProjectedTrack(IdEta).value_or(0);
1160 EtaPanelEfficiency = readCdo->getEfficiency(IdEta).value_or(1.);
1161 PhiPanelEfficiency = readCdo->getEfficiency(IdPhi).value_or(1.);
1162 GapEfficiency = readCdo->getGapEfficiency(IdEta).value_or(1.);
1164 if (std::abs(FracDeadStripEta - 1.) < 0.001) {
1165 ATH_MSG_DEBUG(
"Watch out: SPECIAL CASE: Read from Cool: FracDeadStripEta/Phi "
1166 << FracDeadStripEta <<
"/" << FracDeadStripPhi <<
" RPC_ProjectedTracksEta " << RPC_ProjectedTracksEta
1167 <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency <<
"/" << PhiPanelEfficiency <<
" gapEff " << GapEfficiency
1171 FracDeadStripPhi = 0.;
1172 ATH_MSG_VERBOSE(
"Watch out: SPECIAL CASE: Resetting FracDeadStripPhi " << FracDeadStripPhi <<
" ignoring phi dead strips ");
1180 bool changing =
false;
1181 ATH_MSG_DEBUG(
"Read from Cool: FracDeadStripEta/Phi " << FracDeadStripEta <<
"/" << FracDeadStripPhi <<
" RPC_ProjectedTracksEta "
1182 << RPC_ProjectedTracksEta <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency
1183 <<
"/" << PhiPanelEfficiency <<
" gapEff " << GapEfficiency);
1185 if ((maxGeomEff - FracDeadStripEta) - EtaPanelEfficiency < -0.011) {
1186 ATH_MSG_DEBUG(
"Ineff. from dead strips on Eta Panel larger that measured efficiency: deadFrac="
1188 ATH_MSG_DEBUG(
"... see the corresponding report from RpcDetectorStatusDbTool");
1190 EtaPanelEfficiency = maxGeomEff - FracDeadStripEta;
1194 if ((maxGeomEff - FracDeadStripPhi) - PhiPanelEfficiency < -0.011) {
1195 ATH_MSG_DEBUG(
"Ineff. from dead strips on Phi Panel larger that measured efficiency: deadFrac="
1197 ATH_MSG_DEBUG(
"... see the corresponding report among the warnings of RpcDetectorStatusDbTool");
1199 PhiPanelEfficiency = maxGeomEff - FracDeadStripPhi;
1203 if ((maxGeomEff - FracDeadStripEta * FracDeadStripPhi) - GapEfficiency < -0.011) {
1204 ATH_MSG_DEBUG(
"Ineff. from dead strips on Eta/Phi Panels larger that measured EtaORPhi efficiency: deadFrac="
1205 << FracDeadStripEta * FracDeadStripPhi <<
" EtaORPhi Eff=" << GapEfficiency <<
" for GasGap "
1207 ATH_MSG_DEBUG(
"... see the corresponding report among the warnings of RpcDetectorStatusDbTool");
1209 GapEfficiency = maxGeomEff - FracDeadStripEta * FracDeadStripPhi;
1213 ATH_MSG_DEBUG(
"Rinormalized Values from Cool: FracDeadStripEta/Phi "
1214 << FracDeadStripEta <<
"/" << FracDeadStripPhi <<
" RPC_ProjectedTracksEta " << RPC_ProjectedTracksEta
1215 <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency <<
"/" << PhiPanelEfficiency <<
" gapEff " << GapEfficiency);
1219 if ((FracDeadStripEta > 0.0 && FracDeadStripEta < 1.0) || (FracDeadStripPhi > 0.0 && FracDeadStripPhi < 1.0) || (noEntryInDb)) {
1220 EtaPanelEfficiency = EtaPanelEfficiency / (maxGeomEff - FracDeadStripEta);
1221 PhiPanelEfficiency = PhiPanelEfficiency / (maxGeomEff - FracDeadStripPhi);
1222 GapEfficiency = GapEfficiency / (maxGeomEff - FracDeadStripEta * FracDeadStripPhi);
1224 if (EtaPanelEfficiency > maxGeomEff) EtaPanelEfficiency = maxGeomEff;
1225 if (PhiPanelEfficiency > maxGeomEff) PhiPanelEfficiency = maxGeomEff;
1226 if (GapEfficiency > maxGeomEff) GapEfficiency = maxGeomEff;
1228 if (EtaPanelEfficiency > GapEfficiency) GapEfficiency = EtaPanelEfficiency;
1229 if (PhiPanelEfficiency > GapEfficiency) GapEfficiency = PhiPanelEfficiency;
1230 ATH_MSG_DEBUG(
"Eff Redefined (to correct for deadfrac): FracDeadStripEta/Phi "
1231 <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency <<
"/" << PhiPanelEfficiency <<
" gapEff "
1237 PhiAndEtaEff =
float(EtaPanelEfficiency + PhiPanelEfficiency - GapEfficiency);
1238 if (PhiAndEtaEff < 0.) PhiAndEtaEff = 0.;
1239 OnlyEtaEff =
float(EtaPanelEfficiency - PhiAndEtaEff);
1240 if (OnlyEtaEff < 0.) OnlyEtaEff = 0.;
1241 OnlyPhiEff =
float(PhiPanelEfficiency - PhiAndEtaEff);
1242 if (OnlyPhiEff < 0.) OnlyPhiEff = 0.;
1246 bool applySpecialPatch =
false;
1252 applySpecialPatch =
true;
1254 "Applying special patch for BMS at |eta|=6 lowPt plane -dbbZ=2 and dbPhi=1 ... will use default eff. for Id "
1257 "Applying special patch: THIS HAS TO BE DONE IF /RPC/DQMF/ELEMENT_STATUS tag is "
1258 "RPCDQMFElementStatus_2012_Jaunuary_2");
1264 if (applySpecialPatch || RPC_ProjectedTracksEta < m_CutProjectedTracks || RPC_ProjectedTracksEta > 10000000 ||
1265 EtaPanelEfficiency > 1 || EtaPanelEfficiency < 0 || PhiPanelEfficiency > 1 || PhiPanelEfficiency < 0 || GapEfficiency > 1 ||
1266 GapEfficiency < 0) {
1272 <<
" resetting eff. from cool with default(python) values ");
1289 float effgap = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1290 float s_EtaPanelEfficiency = 1. - FracDeadStripEta;
1291 float s_PhiPanelEfficiency = 1. - FracDeadStripPhi;
1292 float s_PhiAndEtaEff = s_EtaPanelEfficiency * s_PhiPanelEfficiency / effgap;
1293 if (s_PhiAndEtaEff < PhiAndEtaEff) PhiAndEtaEff = s_PhiAndEtaEff;
1294 float s_OnlyEtaEff = s_EtaPanelEfficiency - PhiAndEtaEff;
1295 float s_OnlyPhiEff = s_PhiPanelEfficiency - PhiAndEtaEff;
1297 if (s_OnlyEtaEff < OnlyEtaEff) OnlyEtaEff = s_OnlyEtaEff;
1298 if (s_OnlyPhiEff < OnlyPhiEff) OnlyPhiEff = s_OnlyPhiEff;
1302 float VolEff = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1303 if (VolEff > maxGeomEff) {
1304 PhiAndEtaEff = (PhiAndEtaEff / VolEff) * maxGeomEff;
1305 OnlyEtaEff = (OnlyEtaEff / VolEff) * maxGeomEff;
1306 OnlyPhiEff = (OnlyPhiEff / VolEff) * maxGeomEff;
1315 const int particlePdgId = genparticle->pdg_id();
1317 if ((
static_cast<int>(std::abs(particlePdgId) / 10000000) == 2) && (
static_cast<int>(std::abs(particlePdgId) / 100000) == 200)) {
1320 PhiAndEtaEff = PhiAndEtaEff * eff_sf;
1321 OnlyEtaEff = OnlyEtaEff * eff_sf;
1322 OnlyPhiEff = OnlyPhiEff * eff_sf;
1326 float I0 = PhiAndEtaEff;
1327 float I1 = PhiAndEtaEff + OnlyEtaEff;
1328 float ITot = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1330 float GapEff = ITot ;
1331 float PhiEff = PhiAndEtaEff + OnlyPhiEff;
1332 float EtaEff = PhiAndEtaEff + OnlyEtaEff;
1334 ATH_MSG_DEBUG(
"DetectionEfficiency: Final Efficiency Values applied for "
1336 <<
"=OnlyEtaEff " << OnlyPhiEff <<
"=OnlyPhiEff " << GapEff <<
"=GapEff " << EtaEff <<
"=EtaEff " << PhiEff
1339 float rndmEff = CLHEP::RandFlat::shoot(rndmEngine, 1);
1344 }
else if ((I0 <= rndmEff) && (rndmEff < I1)) {
1347 }
else if ((I1 <= rndmEff) && (rndmEff <= ITot)) {
1355 return std::make_pair(etaStripOn, phiStripOn);
1360 const Identifier& idRpcStrip,
1362 CLHEP::HepRandomEngine* rndmEngine)
const {
1363 ATH_MSG_DEBUG(
"RpcDigitizationTool::in determineClusterSize");
1367 int ClusterSize = 1;
1369 double FracClusterSize1{1.}, FracClusterSize2{0.}, MeanClusterSize{1.},
1370 FracClusterSizeTail{0.}, MeanClusterSizeTail{1.},
1371 FracClusterSize2norm{0.};
1425 int RPC_ProjectedTracks = readCdo->getProjectedTrack(Id).value_or(0);
1426 FracClusterSize1 = readCdo->getFracClusterSize1(Id).value_or(1.);
1427 FracClusterSize2 = readCdo->getFracClusterSize2(Id).value_or(0.);
1428 MeanClusterSize = readCdo->getMeanClusterSize(Id).value_or(1.);
1431 ATH_MSG_DEBUG(
"FracClusterSize1 and 2 " << FracClusterSize1 <<
" " << FracClusterSize2);
1433 FracClusterSizeTail = 1. - FracClusterSize1 - FracClusterSize2;
1435 MeanClusterSizeTail = MeanClusterSize - FracClusterSize1 - 2 * FracClusterSize2;
1437 ATH_MSG_DEBUG(
"MeanClusterSizeTail and FracClusterSizeTail " << MeanClusterSizeTail <<
" " << FracClusterSizeTail);
1440 if (RPC_ProjectedTracks < m_CutProjectedTracks || RPC_ProjectedTracks > 10000000 || MeanClusterSize >
m_CutMaxClusterSize ||
1441 MeanClusterSize <= 1 || FracClusterSizeTail < 0 || FracClusterSize1 < 0 || FracClusterSize2 < 0 || FracClusterSizeTail > 1 ||
1442 FracClusterSize1 > 1 || FracClusterSize2 > 1) {
1478 FracClusterSize1 =
std::min(FracClusterSize1, 1.);
1479 FracClusterSize2 =
std::min(FracClusterSize2, 1.);
1480 FracClusterSizeTail =
std::min(FracClusterSizeTail, 1.);
1481 float FracTot = FracClusterSize1 + FracClusterSize2 + FracClusterSizeTail;
1482 if (FracTot != 1. && FracTot > 0) {
1483 FracClusterSize1 = FracClusterSize1 / FracTot;
1484 FracClusterSize2 = FracClusterSize2 / FracTot;
1485 FracClusterSizeTail = FracClusterSizeTail / FracTot;
1487 if (MeanClusterSizeTail < 0 || MeanClusterSizeTail > 10) MeanClusterSizeTail = 1;
1489 ATH_MSG_VERBOSE(
"ClusterSize Final " << FracClusterSize1 <<
" FracClusterSize1 " << FracClusterSize2 <<
" FracClusterSize2 "
1490 << FracClusterSizeTail <<
" " << FracClusterSizeTail <<
" MeanClusterSizeTail "
1491 << MeanClusterSizeTail);
1493 float FracClusterSize1plus2 = FracClusterSize1 + FracClusterSize2;
1494 float ITot = FracClusterSize1 + FracClusterSize2 + FracClusterSizeTail;
1496 if (FracClusterSize1plus2 != 0) {
1498 FracClusterSize2norm = FracClusterSize2 / FracClusterSize1plus2;
1501 float rndmCS = CLHEP::RandFlat::shoot(rndmEngine, ITot);
1505 if (rndmCS < FracClusterSize1plus2) {
1507 if (xstripnorm <= FracClusterSize2norm / 2. * 1.3) {
1509 }
else if ((1.0 - FracClusterSize2norm / 2. * 1.3) <= xstripnorm) {
1515 float rndmCS1_2 = CLHEP::RandFlat::shoot(rndmEngine, 1);
1516 ClusterSize = 1 + (rndmCS1_2 < FracClusterSize2norm);
1519 }
else if ((FracClusterSize1plus2 <= rndmCS) && (rndmCS <= ITot)) {
1521 ClusterSize +=
int(CLHEP::RandExponential::shoot(rndmEngine, MeanClusterSizeTail));
1522 float rndmLR = CLHEP::RandFlat::shoot(rndmEngine, 1.0);
1523 if (rndmLR > 0.5) ClusterSize = -ClusterSize;
1529 if (rndmCS < FracClusterSize1) {
1531 }
else if (rndmCS < FracClusterSize1 + FracClusterSize2) {
1534 ClusterSize =
int(CLHEP::RandExponential::shoot(rndmEngine, MeanClusterSizeTail));
1536 ClusterSize =
std::max(ClusterSize, 1);
1537 if (ClusterSize > 1) {
1538 float rndmLR = CLHEP::RandFlat::shoot(rndmEngine, 1.0);
1539 if (rndmLR > 0.5) ClusterSize = -ClusterSize;
1547 double qcharge = 1.;
1548 const int particlePdgId = genParticle->pdg_id();
1550 qcharge = (
static_cast<double>((std::abs(particlePdgId) / 1000) % 100)) / (
static_cast<double>((std::abs(particlePdgId) / 10) % 100));
1551 qcharge = ((
static_cast<double>((
static_cast<int>(qcharge * 100))))) / 100;
1552 if (particlePdgId < 0.0) qcharge = -qcharge;
1554 const double QPx = genParticle->momentum().px();
1555 const double QPy = genParticle->momentum().py();
1556 const double QPz = genParticle->momentum().pz();
1557 const double QE = genParticle->momentum().e();
1559 const double QP = std::hypot(QPx, QPy, QPz);
1560 const double QM = QM2 >=0 ? std::sqrt(QM2) : -1.;
1562 const double qbetagamma = QM > 0. ? QP / QM : -1.;
1566 for (
int i = 0;
i < 12;
i++) {
1567 if (Charge[
i] == std::abs(qcharge)) {
1572 int i_v = -99, j_v = 99;
1573 if (qbetagamma != -1) {
1574 for (
int i = 0;
i < 15;
i++) {
1575 if (Velocity[
i] <= qbetagamma) { i_v =
i; }
1577 for (
int i = 14;
i >= 0;
i--) {
1578 if (Velocity[
i] >= qbetagamma) { j_v =
i; }
1583 double eff_fcp = 1.0, eff_muon = 1.0;
1584 if (i_e >= 0 && i_e <= 11) {
1585 if (validIndex(j_v, N_Velocity) && validIndex(i_v, N_Velocity) && (j_v - i_v) == 1) {
1586 const double delta_v = Velocity[i_v] - Velocity[j_v];
1587 eff_fcp = (Eff_garfield[i_e][i_v] - Eff_garfield[i_e][j_v]) / delta_v * qbetagamma +
1588 (Eff_garfield[i_e][j_v] * Velocity[i_v] - Eff_garfield[i_e][i_v] * Velocity[j_v]) / delta_v;
1589 eff_muon = (Eff_garfield[11][i_v] - Eff_garfield[11][j_v]) / delta_v * qbetagamma +
1590 (Eff_garfield[11][j_v] * Velocity[i_v] - Eff_garfield[11][i_v] * Velocity[j_v]) / delta_v;
1591 }
else if (i_v == 14 && j_v == 99) {
1592 eff_fcp = Eff_garfield[i_e][14];
1593 eff_muon = Eff_garfield[11][14];
1594 }
else if (i_v == -99 && j_v == 0) {
1595 eff_fcp = Eff_garfield[i_e][0];
1596 eff_muon = Eff_garfield[11][0];
1598 ATH_MSG_WARNING(
"Wrong particle with unknown velocity! Scale factor is set to be 1.");
1601 ATH_MSG_WARNING(
"Wrong particle with unknown charge! Scale factor is set to be 1.");
1604 const double eff_SF = eff_fcp / eff_muon;
1611 constexpr
double tot_mean_narrow = 16.;
1612 constexpr
double tot_sigma_narrow = 2.;
1613 constexpr
double tot_mean_wide = 15.;
1614 constexpr
double tot_sigma_wide = 4.5;
1618 if (CLHEP::RandFlat::shoot(rndmEngine)<0.75) {
1619 thetot = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot_mean_narrow, tot_sigma_narrow);
1621 thetot = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot_mean_wide, tot_sigma_wide);
1624 return (thetot > 0.) ? thetot : 0.;