18 #include "GaudiKernel/SystemOfUnits.h"
19 #include "GaudiKernel/PhysicalConstants.h"
21 #include "GeoModelHelpers/TransformToStringConverter.h"
42 #include "GeoModelKernel/throwExcept.h"
45 #include "CLHEP/Random/RandExponential.h"
46 #include "CLHEP/Random/RandFlat.h"
47 #include "CLHEP/Random/RandGaussZiggurat.h"
63 constexpr
int N_Charge = 12;
64 constexpr
int N_Velocity = 15;
65 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};
66 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};
67 constexpr
double Eff_garfield[N_Charge][N_Velocity] = {
68 {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},
69 {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},
70 {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},
71 {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},
72 {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},
73 {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},
74 {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},
75 {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},
76 {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},
77 {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},
78 {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},
79 {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}};
81 validIndex(
int idx,
int arraySize){
82 return (
idx>=0) and (
idx<arraySize);
88 constexpr
double SIG_VEL = 4.8;
139 return StatusCode::FAILURE;
156 ATH_MSG_DEBUG(
"Ready to read parameters for cluster simulation from file");
174 return StatusCode::SUCCESS;
180 SmartIF<IGeoModelSvc> geoModel{Gaudi::svcLocator()->service(
"GeoModelSvc")};
183 return StatusCode::FAILURE;
187 std::string atlasVersion = geoModel->atlasVersion();
189 SmartIF<IRDBAccessSvc> rdbAccess{Gaudi::svcLocator()->service(
"RDBAccessSvc")};
192 return StatusCode::FAILURE;
198 std::string configVal =
"";
200 IRDBRecordset_ptr atlasCommonRec = rdbAccess->getRecordsetPtr(
"AtlasCommon", atlasVersion,
"ATLAS");
201 if (atlasCommonRec->size() == 0) {
204 configVal = (*atlasCommonRec)[0]->getString(
"CONFIG");
205 ATH_MSG_INFO(
"From DD Database, Configuration is " << configVal);
206 if (configVal ==
"RUN1") {
208 }
else if (configVal ==
"RUN2") {
210 }
else if (configVal ==
"RUN3") {
212 }
else if (configVal ==
"RUN4") {
216 ATH_MSG_FATAL(
"Unexpected value for geometry config read from the database: " << configVal);
217 return StatusCode::FAILURE;
224 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN1 or MuonGeometry = R.06");
226 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN2 or MuonGeometry = R.07");
227 else if (
run == Run3)
228 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN3 or MuonGeometry = R.09");
229 else if (
run == Run4)
230 ATH_MSG_INFO(
"From Geometry DB: MuonSpectrometer configuration is: RUN4 or MuonGeometry = R.10");
243 if (configVal ==
"RUN1") {
262 ATH_MSG_INFO(
"Run3/4: configuration parameter not from COOL");
269 ATH_MSG_INFO(
"RPC Run1/2/3-dependent configuration is enforced");
271 ATH_MSG_WARNING(
"Run1/2/3-dependent configuration is bypassed; be careful with option settings");
282 return StatusCode::SUCCESS;
285 template <
class CondType>
288 const CondType* & condPtr)
const {
291 ATH_MSG_DEBUG(
"No key has been configured for object "<<
typeid(CondType).
name()<<
". Clear pointer");
293 return StatusCode::SUCCESS;
296 if (!readHandle.isValid()){
298 return StatusCode::FAILURE;
300 condPtr = readHandle.cptr();
301 return StatusCode::SUCCESS;
310 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>();
313 return StatusCode::SUCCESS;
321 TimedHitCollList hitCollList;
324 hitCollList.empty()) {
326 return StatusCode::FAILURE;
335 for (; iColl != endColl; ++iColl) {
339 ATH_MSG_DEBUG(
"RPCSimHitCollection found with " << hitCollPtr->
size() <<
" hits");
342 m_thpcRPC->insert(timeIndex, hitCollPtr);
346 return StatusCode::SUCCESS;
363 if (!hitCollection.
isValid()) {
364 ATH_MSG_ERROR(
"Could not get RPCSimHitCollection container " << hitCollection.
name() <<
" from store "
365 << hitCollection.
store());
366 return StatusCode::FAILURE;
370 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>(1);
372 ATH_MSG_DEBUG(
"RPCSimHitCollection found with " << hitCollection->
size() <<
" hits");
374 return StatusCode::SUCCESS;
377 TimedHitCollList hitCollList;
381 return StatusCode::FAILURE;
383 if (hitCollList.empty()) {
385 return StatusCode::FAILURE;
391 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>();
395 while (iColl != endColl) {
397 m_thpcRPC->insert(iColl->first, p_collection);
402 return StatusCode::SUCCESS;
417 ATH_CHECK(sdoContainer.
record(std::make_unique<MuonSimDataCollection>()));
427 for (
size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
428 if (collections[coll_hash]) {
454 ATH_CHECK(sdoContainer.
record(std::make_unique<MuonSimDataCollection>()));
463 if (StatusCode::FAILURE ==
status) {
471 for (
size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
472 if (collections[coll_hash]) {
486 CLHEP::HepRandomEngine* rndmEngine = rngWrapper->
getEngine(ctx);
492 std::unique_ptr<RPCSimHitCollection> inputSimHitColl{std::make_unique<RPCSimHitCollection>(
"RPC_Hits")};
502 return StatusCode::FAILURE;
505 struct SimDataContent {
507 std::vector<MuonSimData::Deposit> deposits;
515 std::map<Identifier, SimDataContent> channelSimDataMap;
526 const int idHit = hit.
RPCid();
528 const double globalHitTime{
hitTime(phit)};
532 const double bunchTime{globalHitTime - hit.
globalTime()};
534 ATH_MSG_DEBUG(
"Global time " << globalHitTime <<
" G4 time " << G4Time <<
" Bunch time " << bunchTime);
537 ATH_MSG_VERBOSE(
"Validation: globalHitTime, G4Time, BCtime = " << globalHitTime <<
" " << G4Time <<
" " << bunchTime);
538 inputSimHitColl->Emplace(idHit, globalHitTime, hit.
localPosition(),
578 bool isValidEta{
false}, isValidPhi{
false};
581 if (!isValidEta || !isValidPhi) {
584 <<
" doubletR " <<
doubletR <<
" doubletZ " << doubletZ <<
" doubletPhi " <<
doubletPhi <<
" gasGap "
593 const double corrtimejitter = tmp_CorrJitter > 0.01 ?
594 CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0., tmp_CorrJitter) : 0.;
602 Amg::intersect<3>(hit.
localPosition(), hitDir, Amg::Vector3D::UnitX(), 0).value_or(0) * hitDir;
604 std::array<int, 3> pcseta =
physicalClusterSize(ctx, reEle, idpaneleta, gapCentre, rndmEngine);
605 ATH_MSG_VERBOSE(
"Simulated cluster on eta panel: size/first/last= " << pcseta[0] <<
"/" << pcseta[1] <<
"/" << pcseta[2]);
606 std::array<int, 3> pcsphi =
physicalClusterSize(ctx, reEle, idpanelphi, gapCentre, rndmEngine);
607 ATH_MSG_VERBOSE(
"Simulated cluster on phi panel: size/first/last= " << pcsphi[0] <<
"/" << pcsphi[1] <<
"/" << pcsphi[2]);
616 const auto [etaStripOn, phiStripOn] =
detectionEfficiency(ctx, idpaneleta, idpanelphi, rndmEngine, particleLink);
617 ATH_MSG_DEBUG(
"SetPhiOn " << phiStripOn <<
" SetEtaOn " << etaStripOn);
619 for (
bool imeasphi : {
false,
true}) {
620 if (!imeasphi && (!etaStripOn || !isValidEta))
continue;
621 if (imeasphi && (!phiStripOn || !isValidPhi))
continue;
625 const Identifier& atlasId = !imeasphi ? atlasRpcIdeta : atlasRpcIdphi;
626 std::array<int, 3>
pcs{!imeasphi ? pcseta : pcsphi};
629 <<
" doubletR " <<
doubletR <<
" doubletZ " << doubletZ <<
" doubletPhi " <<
doubletPhi
630 <<
" gasGap " <<
gasGap <<
" measphi " << imeasphi);
657 double tns = G4Time + proptime + corrtimejitter;
658 ATH_MSG_VERBOSE(
"TOF+propagation time " << tns <<
" /s where proptime " << proptime <<
"/s");
660 double time = tns + bunchTime;
666 double*
b =
reinterpret_cast<double*
>(&packedMCword);
678 if (channelSimDataMap.find(atlasId) == channelSimDataMap.end()) {
679 SimDataContent&
content = channelSimDataMap[atlasId];
681 content.deposits.push_back(deposit);
697 for (
int clus =
pcs[1]; clus <=
pcs[2]; ++clus) {
702 <<
" "<<
doubletPhi<<
" "<<
gasGap <<
" "<< imeasphi<<
" "<< clus<<
" is invalid");
708 ATH_MSG_WARNING(
"Temporary skipping creation of RPC digit for stationName="
710 <<
", doubletZ=" << doubletZ <<
", doubletPhi=" <<
doubletPhi <<
", gasGap=" <<
gasGap
711 <<
", measuresPhi=" << imeasphi <<
", strip=" << clus <<
", cf. ATLASRECTS-6124");
712 return StatusCode::SUCCESS;
716 return StatusCode::FAILURE;
725 std::vector<MuonSimData::Deposit> newdeps;
726 newdeps.push_back(deposit);
736 for (
auto it = channelSimDataMap.begin();
it != channelSimDataMap.end(); ++
it) {
740 auto insertResult = sdoContainer->insert(std::make_pair(
it->first,
simData));
741 if (!insertResult.second)
742 ATH_MSG_WARNING(
"Attention: this sdo is not recorded, since the identifier already exists in the sdoContainer map");
758 const std::vector<MuonSimData::Deposit> theDeps = (*map_iter).second;
762 std::multimap<double, MuonSimData::Deposit>
times;
765 for (
unsigned int k = 0;
k < theDeps.size();
k++) {
766 double time = theDeps[
k].second.secondEntry();
767 times.insert(std::multimap<double, MuonSimData::Deposit>::value_type(
time, theDeps[
k]));
777 double last_time = -10000;
778 for (; map_dep_iter !=
times.end(); ++map_dep_iter) {
779 double currTime = (*map_dep_iter).first;
785 if (sdoContainer->find(theId) != sdoContainer->end())
787 std::map<Identifier, MuonSimData>::const_iterator
it = sdoContainer->find(theId);
788 std::vector<MuonSimData::Deposit> deps = ((*it).second).getdeposits();
789 deps.push_back((*map_dep_iter).second);
792 std::vector<MuonSimData::Deposit> deposits;
793 deposits.push_back((*map_dep_iter).second);
795 sdoContainer->insert(std::make_pair(theId,
MuonSimData(deposits, 0)));
796 if (!insertResult.second)
798 "Attention TEMP: this sdo is not recorded, since the identifier already exists in the sdoContainer map");
802 if (std::abs(currTime - last_time) > (
m_deadTime)) {
803 ATH_MSG_DEBUG(
"deposit with time " << currTime <<
" is distant enough from previous (if any) hit on teh same strip");
804 last_time = (*map_dep_iter).first;
807 double uncorrjitter = 0;
810 if (tmp_UncorrJitter > 0.01) uncorrjitter = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0., tmp_UncorrJitter);
820 double newDigit_time = currTime + uncorrjitter +
m_rpc_time_shift -
tp - propTimeFromStripCenter;
822 double digi_ToT = -1.;
825 ATH_MSG_VERBOSE(
"last_time=currTime " << last_time <<
" jitter " << uncorrjitter <<
" TOFcorrection " <<
tp <<
" shift "
829 bool outsideDigitizationWindow =
outsideWindow(newDigit_time);
830 if (outsideDigitizationWindow) {
831 ATH_MSG_VERBOSE(
"hit outside digitization window - do not produce digits");
840 last_time = (*map_dep_iter).first;
842 std::unique_ptr<RpcDigit> newDigit = std::make_unique<RpcDigit>(theId, newDigit_time, digi_ToT,
false);
847 IdentifierHash coll_hash;
849 ATH_MSG_ERROR(
"Unable to get RPC hash id from RPC Digit collection "
850 <<
"context begin_index = " << rpcContext.
begin_index()
851 <<
" context end_index = " << rpcContext.
end_index() <<
" the identifier is ");
859 if (coll_hash >= collections.size()) {
860 collections.resize (coll_hash+1);
862 digitCollection = collections[coll_hash].
get();
863 if (!digitCollection) {
864 collections[coll_hash] = std::make_unique<RpcDigitCollection>(elemId, coll_hash);
865 digitCollection = collections[coll_hash].
get();
867 digitCollection->
push_back(std::move(newDigit));
871 if (sdoContainer->find(theId) != sdoContainer->end()) {
872 std::map<Identifier, MuonSimData>::const_iterator
it = sdoContainer->find(theId);
873 std::vector<MuonSimData::Deposit> deps = ((*it).second).getdeposits();
874 deps.push_back((*map_dep_iter).second);
876 std::vector<MuonSimData::Deposit> deposits;
877 deposits.push_back((*map_dep_iter).second);
879 sdoContainer->insert(std::make_pair(theId,
MuonSimData(deposits, 0)));
880 if (!insertResult.second)
882 "Attention: this sdo is not recorded, since teh identifier already exists in the sdoContainer map");
887 ATH_MSG_DEBUG(
"discarding digit due to dead time: " << (*map_dep_iter).first <<
" " << last_time);
896 ATH_CHECK(validHandle.record(std::move(inputSimHitColl)));
899 return StatusCode::SUCCESS;
927 CLHEP::HepRandomEngine* rndmEngine)
const {
930 std::array<int, 3>
result{};
936 const double pitch= ele->
StripPitch(measuresPhi);
939 const int nstrip = ele->
stripNumber(position.block<2,1>(0,0),
id);
940 const int numStrips = ele->
Nstrips(measuresPhi);
945 if (nstrip < 1 || nstrip > numStrips) {
946 return make_array<int, 3>(-1);
949 float xstripnorm = (locStripPos -position).
x() / pitch ;
962 std::array<int, 3>&&
pcs,
970 }
else if (
pcs[0] == 2) {
972 }
else if (
pcs[0] > 2) {
974 if (fmod(
pcs[0], 2) == 0)
pcs[1] =
pcs[1] + 1;
976 }
else if (
pcs[0] < -2) {
983 pcs[1] = std::clamp(
pcs[1], 1, nstrips);
984 pcs[2] = std::clamp(
pcs[2], 1, nstrips);
1004 return std::abs(
distance * SIG_VEL * 1.
e-3);
1011 ATH_MSG_WARNING(
"A poblem: packing a propagation time <0 " << proptime <<
" redefine it as 0");
1014 long long int new_proptime =
int(proptime * 10) & 0xff;
1020 long long int new_bctime =
int((bctime + 300.) * 10.) & 0xffff;
1025 long long int new_posy =
int((posy + 1500.) * 10.) & 0xffff;
1030 long long int new_posz =
int((posz + 1500.) * 10.) & 0xffff;
1032 return (new_proptime + (new_bctime << 8) + (new_posy << 24) + (new_posz << 40));
1038 using Repacker =
union
1046 MCTruth.dWord = theWord;
1047 proptime = ((MCTruth.iWord) & 0x00000000000000ffLL) / 10.;
1048 bctime = (((MCTruth.iWord) & 0x0000000000ffff00LL) >> 8) / 10.;
1049 posy = (((MCTruth.iWord) & 0x000000ffff000000LL) >> 24) / 10.;
1050 posz = (((MCTruth.iWord) & 0x00ffff0000000000LL) >> 40) / 10.;
1053 bctime = bctime - 300.;
1054 posy = posy - 1500.;
1055 posz = posz - 1500.;
1061 SmartIF<ITagInfoMgr> tagInfoMgr{Gaudi::svcLocator()->service(
"TagInfoMgr")};
1062 if (!tagInfoMgr) {
return StatusCode::FAILURE; }
1064 std::string RpctimeSchema =
"";
1065 std::stringstream RpctimeShift;
1069 RpctimeSchema =
"Datalike_TOFoff_TimeShift" + RpctimeShift.str() +
"nsec";
1071 RpctimeSchema =
"G4like_TOFon_TimeShift" + RpctimeShift.str() +
"nsec";
1076 if (
sc.isFailure()) {
1083 return StatusCode::SUCCESS;
1091 CLHEP::HepRandomEngine* rndmEngine,
1096 ATH_MSG_DEBUG(
"RpcDigitizationTool::in DetectionEfficiency");
1104 float maxGeomEff{0.99}, PhiAndEtaEff{0.99}, OnlyEtaEff{0.f}, OnlyPhiEff{0.f};
1113 return std::make_pair(
false,
false);
1118 return std::make_pair(
true,
true);
1120 bool etaStripOn{
true}, phiStripOn{
true};
1161 ATH_MSG_DEBUG(
"Efficiencies and cluster size + dead strips will be extracted from COOL");
1163 double FracDeadStripEta{0.}, FracDeadStripPhi{0.};
1164 double EtaPanelEfficiency{1.}, PhiPanelEfficiency{1.}, GapEfficiency{1.};
1165 int RPC_ProjectedTracksEta = 0;
1167 std::optional<double> fracDeadStripEtaFromCOOL = readCdo->getFracDeadStrip(IdEta);
1168 std::optional<double> fracDeadStripPhiFromCOOL = readCdo->getFracDeadStrip(IdPhi);
1170 bool noEntryInDb = !fracDeadStripEtaFromCOOL || !fracDeadStripPhiFromCOOL;
1172 FracDeadStripEta = fracDeadStripEtaFromCOOL.value_or(0.);
1173 FracDeadStripPhi = fracDeadStripPhiFromCOOL.value_or(0.);
1174 RPC_ProjectedTracksEta = readCdo->getProjectedTrack(IdEta).value_or(0);
1176 EtaPanelEfficiency = readCdo->getEfficiency(IdEta).value_or(1.);
1177 PhiPanelEfficiency = readCdo->getEfficiency(IdPhi).value_or(1.);
1178 GapEfficiency = readCdo->getGapEfficiency(IdEta).value_or(1.);
1180 if (std::abs(FracDeadStripEta - 1.) < 0.001) {
1181 ATH_MSG_DEBUG(
"Watch out: SPECIAL CASE: Read from Cool: FracDeadStripEta/Phi "
1182 << FracDeadStripEta <<
"/" << FracDeadStripPhi <<
" RPC_ProjectedTracksEta " << RPC_ProjectedTracksEta
1183 <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency <<
"/" << PhiPanelEfficiency <<
" gapEff " << GapEfficiency
1187 FracDeadStripPhi = 0.;
1188 ATH_MSG_VERBOSE(
"Watch out: SPECIAL CASE: Resetting FracDeadStripPhi " << FracDeadStripPhi <<
" ignoring phi dead strips ");
1196 bool changing =
false;
1197 ATH_MSG_DEBUG(
"Read from Cool: FracDeadStripEta/Phi " << FracDeadStripEta <<
"/" << FracDeadStripPhi <<
" RPC_ProjectedTracksEta "
1198 << RPC_ProjectedTracksEta <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency
1199 <<
"/" << PhiPanelEfficiency <<
" gapEff " << GapEfficiency);
1201 if ((maxGeomEff - FracDeadStripEta) - EtaPanelEfficiency < -0.011) {
1202 ATH_MSG_DEBUG(
"Ineff. from dead strips on Eta Panel larger that measured efficiency: deadFrac="
1204 ATH_MSG_DEBUG(
"... see the corresponding report from RpcDetectorStatusDbTool");
1206 EtaPanelEfficiency = maxGeomEff - FracDeadStripEta;
1210 if ((maxGeomEff - FracDeadStripPhi) - PhiPanelEfficiency < -0.011) {
1211 ATH_MSG_DEBUG(
"Ineff. from dead strips on Phi Panel larger that measured efficiency: deadFrac="
1213 ATH_MSG_DEBUG(
"... see the corresponding report among the warnings of RpcDetectorStatusDbTool");
1215 PhiPanelEfficiency = maxGeomEff - FracDeadStripPhi;
1219 if ((maxGeomEff - FracDeadStripEta * FracDeadStripPhi) - GapEfficiency < -0.011) {
1220 ATH_MSG_DEBUG(
"Ineff. from dead strips on Eta/Phi Panels larger that measured EtaORPhi efficiency: deadFrac="
1221 << FracDeadStripEta * FracDeadStripPhi <<
" EtaORPhi Eff=" << GapEfficiency <<
" for GasGap "
1223 ATH_MSG_DEBUG(
"... see the corresponding report among the warnings of RpcDetectorStatusDbTool");
1225 GapEfficiency = maxGeomEff - FracDeadStripEta * FracDeadStripPhi;
1229 ATH_MSG_DEBUG(
"Rinormalized Values from Cool: FracDeadStripEta/Phi "
1230 << FracDeadStripEta <<
"/" << FracDeadStripPhi <<
" RPC_ProjectedTracksEta " << RPC_ProjectedTracksEta
1231 <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency <<
"/" << PhiPanelEfficiency <<
" gapEff " << GapEfficiency);
1235 if ((FracDeadStripEta > 0.0 && FracDeadStripEta < 1.0) || (FracDeadStripPhi > 0.0 && FracDeadStripPhi < 1.0) || (noEntryInDb)) {
1236 EtaPanelEfficiency = EtaPanelEfficiency / (maxGeomEff - FracDeadStripEta);
1237 PhiPanelEfficiency = PhiPanelEfficiency / (maxGeomEff - FracDeadStripPhi);
1238 GapEfficiency = GapEfficiency / (maxGeomEff - FracDeadStripEta * FracDeadStripPhi);
1240 if (EtaPanelEfficiency > maxGeomEff) EtaPanelEfficiency = maxGeomEff;
1241 if (PhiPanelEfficiency > maxGeomEff) PhiPanelEfficiency = maxGeomEff;
1242 if (GapEfficiency > maxGeomEff) GapEfficiency = maxGeomEff;
1244 if (EtaPanelEfficiency > GapEfficiency) GapEfficiency = EtaPanelEfficiency;
1245 if (PhiPanelEfficiency > GapEfficiency) GapEfficiency = PhiPanelEfficiency;
1246 ATH_MSG_DEBUG(
"Eff Redefined (to correct for deadfrac): FracDeadStripEta/Phi "
1247 <<
" Eta/PhiPanelEfficiency " << EtaPanelEfficiency <<
"/" << PhiPanelEfficiency <<
" gapEff "
1253 PhiAndEtaEff =
float(EtaPanelEfficiency + PhiPanelEfficiency - GapEfficiency);
1254 if (PhiAndEtaEff < 0.) PhiAndEtaEff = 0.;
1255 OnlyEtaEff =
float(EtaPanelEfficiency - PhiAndEtaEff);
1256 if (OnlyEtaEff < 0.) OnlyEtaEff = 0.;
1257 OnlyPhiEff =
float(PhiPanelEfficiency - PhiAndEtaEff);
1258 if (OnlyPhiEff < 0.) OnlyPhiEff = 0.;
1262 bool applySpecialPatch =
false;
1268 applySpecialPatch =
true;
1270 "Applying special patch for BMS at |eta|=6 lowPt plane -dbbZ=2 and dbPhi=1 ... will use default eff. for Id "
1273 "Applying special patch: THIS HAS TO BE DONE IF /RPC/DQMF/ELEMENT_STATUS tag is "
1274 "RPCDQMFElementStatus_2012_Jaunuary_2");
1280 if (applySpecialPatch || RPC_ProjectedTracksEta < m_CutProjectedTracks || RPC_ProjectedTracksEta > 10000000 ||
1281 EtaPanelEfficiency > 1 || EtaPanelEfficiency < 0 || PhiPanelEfficiency > 1 || PhiPanelEfficiency < 0 || GapEfficiency > 1 ||
1282 GapEfficiency < 0) {
1288 <<
" resetting eff. from cool with default(python) values ");
1305 float effgap = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1306 float s_EtaPanelEfficiency = 1. - FracDeadStripEta;
1307 float s_PhiPanelEfficiency = 1. - FracDeadStripPhi;
1308 float s_PhiAndEtaEff = s_EtaPanelEfficiency * s_PhiPanelEfficiency / effgap;
1309 if (s_PhiAndEtaEff < PhiAndEtaEff) PhiAndEtaEff = s_PhiAndEtaEff;
1310 float s_OnlyEtaEff = s_EtaPanelEfficiency - PhiAndEtaEff;
1311 float s_OnlyPhiEff = s_PhiPanelEfficiency - PhiAndEtaEff;
1313 if (s_OnlyEtaEff < OnlyEtaEff) OnlyEtaEff = s_OnlyEtaEff;
1314 if (s_OnlyPhiEff < OnlyPhiEff) OnlyPhiEff = s_OnlyPhiEff;
1318 float VolEff = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1319 if (VolEff > maxGeomEff) {
1320 PhiAndEtaEff = (PhiAndEtaEff / VolEff) * maxGeomEff;
1321 OnlyEtaEff = (OnlyEtaEff / VolEff) * maxGeomEff;
1322 OnlyPhiEff = (OnlyPhiEff / VolEff) * maxGeomEff;
1335 PhiAndEtaEff = PhiAndEtaEff * eff_sf;
1336 OnlyEtaEff = OnlyEtaEff * eff_sf;
1337 OnlyPhiEff = OnlyPhiEff * eff_sf;
1341 float I0 = PhiAndEtaEff;
1342 float I1 = PhiAndEtaEff + OnlyEtaEff;
1343 float ITot = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1345 float GapEff = ITot ;
1346 float PhiEff = PhiAndEtaEff + OnlyPhiEff;
1347 float EtaEff = PhiAndEtaEff + OnlyEtaEff;
1349 ATH_MSG_DEBUG(
"DetectionEfficiency: Final Efficiency Values applied for "
1351 <<
"=OnlyEtaEff " << OnlyPhiEff <<
"=OnlyPhiEff " << GapEff <<
"=GapEff " << EtaEff <<
"=EtaEff " << PhiEff
1354 float rndmEff = CLHEP::RandFlat::shoot(rndmEngine, 1);
1359 }
else if ((I0 <= rndmEff) && (rndmEff < I1)) {
1362 }
else if ((I1 <= rndmEff) && (rndmEff <= ITot)) {
1370 return std::make_pair(etaStripOn, phiStripOn);
1377 CLHEP::HepRandomEngine* rndmEngine)
const {
1378 ATH_MSG_DEBUG(
"RpcDigitizationTool::in determineClusterSize");
1382 int ClusterSize = 1;
1384 double FracClusterSize1{1.}, FracClusterSize2{0.}, MeanClusterSize{1.},
1385 FracClusterSizeTail{0.}, MeanClusterSizeTail{1.},
1386 FracClusterSize2norm{0.};
1440 int RPC_ProjectedTracks = readCdo->getProjectedTrack(Id).value_or(0);
1441 FracClusterSize1 = readCdo->getFracClusterSize1(Id).value_or(1.);
1442 FracClusterSize2 = readCdo->getFracClusterSize2(Id).value_or(0.);
1443 MeanClusterSize = readCdo->getMeanClusterSize(Id).value_or(1.);
1446 ATH_MSG_DEBUG(
"FracClusterSize1 and 2 " << FracClusterSize1 <<
" " << FracClusterSize2);
1448 FracClusterSizeTail = 1. - FracClusterSize1 - FracClusterSize2;
1450 MeanClusterSizeTail = MeanClusterSize - FracClusterSize1 - 2 * FracClusterSize2;
1452 ATH_MSG_DEBUG(
"MeanClusterSizeTail and FracClusterSizeTail " << MeanClusterSizeTail <<
" " << FracClusterSizeTail);
1455 if (RPC_ProjectedTracks < m_CutProjectedTracks || RPC_ProjectedTracks > 10000000 || MeanClusterSize >
m_CutMaxClusterSize ||
1456 MeanClusterSize <= 1 || FracClusterSizeTail < 0 || FracClusterSize1 < 0 || FracClusterSize2 < 0 || FracClusterSizeTail > 1 ||
1457 FracClusterSize1 > 1 || FracClusterSize2 > 1) {
1493 FracClusterSize1 =
std::min(FracClusterSize1, 1.);
1494 FracClusterSize2 =
std::min(FracClusterSize2, 1.);
1495 FracClusterSizeTail =
std::min(FracClusterSizeTail, 1.);
1496 float FracTot = FracClusterSize1 + FracClusterSize2 + FracClusterSizeTail;
1497 if (FracTot != 1. && FracTot > 0) {
1498 FracClusterSize1 = FracClusterSize1 / FracTot;
1499 FracClusterSize2 = FracClusterSize2 / FracTot;
1500 FracClusterSizeTail = FracClusterSizeTail / FracTot;
1502 if (MeanClusterSizeTail < 0 || MeanClusterSizeTail > 10) MeanClusterSizeTail = 1;
1504 ATH_MSG_VERBOSE(
"ClusterSize Final " << FracClusterSize1 <<
" FracClusterSize1 " << FracClusterSize2 <<
" FracClusterSize2 "
1505 << FracClusterSizeTail <<
" " << FracClusterSizeTail <<
" MeanClusterSizeTail "
1506 << MeanClusterSizeTail);
1508 float FracClusterSize1plus2 = FracClusterSize1 + FracClusterSize2;
1509 float ITot = FracClusterSize1 + FracClusterSize2 + FracClusterSizeTail;
1511 if (FracClusterSize1plus2 != 0) {
1513 FracClusterSize2norm = FracClusterSize2 / FracClusterSize1plus2;
1516 float rndmCS = CLHEP::RandFlat::shoot(rndmEngine, ITot);
1520 if (rndmCS < FracClusterSize1plus2) {
1522 if (xstripnorm <= FracClusterSize2norm / 2. * 1.3) {
1524 }
else if ((1.0 - FracClusterSize2norm / 2. * 1.3) <= xstripnorm) {
1530 float rndmCS1_2 = CLHEP::RandFlat::shoot(rndmEngine, 1);
1531 ClusterSize = 1 + (rndmCS1_2 < FracClusterSize2norm);
1534 }
else if ((FracClusterSize1plus2 <= rndmCS) && (rndmCS <= ITot)) {
1536 ClusterSize +=
int(CLHEP::RandExponential::shoot(rndmEngine, MeanClusterSizeTail));
1537 float rndmLR = CLHEP::RandFlat::shoot(rndmEngine, 1.0);
1538 if (rndmLR > 0.5) ClusterSize = -ClusterSize;
1544 if (rndmCS < FracClusterSize1) {
1546 }
else if (rndmCS < FracClusterSize1 + FracClusterSize2) {
1549 ClusterSize =
int(CLHEP::RandExponential::shoot(rndmEngine, MeanClusterSizeTail));
1551 ClusterSize =
std::max(ClusterSize, 1);
1552 if (ClusterSize > 1) {
1553 float rndmLR = CLHEP::RandFlat::shoot(rndmEngine, 1.0);
1554 if (rndmLR > 0.5) ClusterSize = -ClusterSize;
1562 double qcharge = 1.;
1563 const int particlePdgId = genParticle->pdg_id();
1565 qcharge = (
static_cast<double>((std::abs(particlePdgId) / 1000) % 100)) / (
static_cast<double>((std::abs(particlePdgId) / 10) % 100));
1566 qcharge = ((
static_cast<double>((
static_cast<int>(qcharge * 100))))) / 100;
1567 if (particlePdgId < 0.0) qcharge = -qcharge;
1569 const double QPx = genParticle->momentum().px();
1570 const double QPy = genParticle->momentum().py();
1571 const double QPz = genParticle->momentum().pz();
1572 const double QE = genParticle->momentum().e();
1574 const double QP = std::hypot(QPx, QPy, QPz);
1575 const double QM = QM2 >=0 ? std::sqrt(QM2) : -1.;
1577 const double qbetagamma = QM > 0. ? QP / QM : -1.;
1581 for (
int i = 0;
i < 12;
i++) {
1582 if (Charge[
i] == std::abs(qcharge)) {
1587 int i_v = -99, j_v = 99;
1588 if (qbetagamma != -1) {
1589 for (
int i = 0;
i < 15;
i++) {
1590 if (Velocity[
i] <= qbetagamma) { i_v =
i; }
1592 for (
int i = 14;
i >= 0;
i--) {
1593 if (Velocity[
i] >= qbetagamma) { j_v =
i; }
1598 double eff_fcp = 1.0, eff_muon = 1.0;
1599 if (i_e >= 0 && i_e <= 11) {
1600 if (validIndex(j_v, N_Velocity) && validIndex(i_v, N_Velocity) && (j_v - i_v) == 1) {
1601 const double delta_v = Velocity[i_v] - Velocity[j_v];
1602 eff_fcp = (Eff_garfield[i_e][i_v] - Eff_garfield[i_e][j_v]) / delta_v * qbetagamma +
1603 (Eff_garfield[i_e][j_v] * Velocity[i_v] - Eff_garfield[i_e][i_v] * Velocity[j_v]) / delta_v;
1604 eff_muon = (Eff_garfield[11][i_v] - Eff_garfield[11][j_v]) / delta_v * qbetagamma +
1605 (Eff_garfield[11][j_v] * Velocity[i_v] - Eff_garfield[11][i_v] * Velocity[j_v]) / delta_v;
1606 }
else if (i_v == 14 && j_v == 99) {
1607 eff_fcp = Eff_garfield[i_e][14];
1608 eff_muon = Eff_garfield[11][14];
1609 }
else if (i_v == -99 && j_v == 0) {
1610 eff_fcp = Eff_garfield[i_e][0];
1611 eff_muon = Eff_garfield[11][0];
1613 ATH_MSG_WARNING(
"Wrong particle with unknown velocity! Scale factor is set to be 1.");
1616 ATH_MSG_WARNING(
"Wrong particle with unknown charge! Scale factor is set to be 1.");
1619 const double eff_SF = eff_fcp / eff_muon;
1626 constexpr
double tot_mean_narrow = 16.;
1627 constexpr
double tot_sigma_narrow = 2.;
1628 constexpr
double tot_mean_wide = 15.;
1629 constexpr
double tot_sigma_wide = 4.5;
1633 if (CLHEP::RandFlat::shoot(rndmEngine)<0.75) {
1634 thetot = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot_mean_narrow, tot_sigma_narrow);
1636 thetot = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot_mean_wide, tot_sigma_wide);
1639 return (thetot > 0.) ? thetot : 0.;