ATLAS Offline Software
Loading...
Searching...
No Matches
RpcDigitizationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6//
7// RpcDigitizationTool
8// ------------
9// Authors:
10// Andrea Di Simone <Andrea.Di.Simone@cern.ch>
11// Gabriele Chiodini <gabriele.chiodini@le.infn.it>
12// Stefania Spagnolo <stefania.spagnolo@le.infn.it>
14
15// Tell clang to optimize assuming that FP operations may trap.
18
20
21// Inputs
22#include "GaudiKernel/SystemOfUnits.h"
23#include "GaudiKernel/PhysicalConstants.h"
25#include "GeoModelHelpers/TransformToStringConverter.h"
28
29// Geometry
34
35// run n. from geometry DB
40
41// Truth
45#include "GeoModelKernel/throwExcept.h"
46// Random Numbers
48#include "CLHEP/Random/RandExponential.h"
49#include "CLHEP/Random/RandFlat.h"
50#include "CLHEP/Random/RandGaussZiggurat.h"
51
52// Core includes
53#include <TString.h> // for Form
54
55#include <atomic>
56#include <fstream>
57#include <iostream>
58#include <sstream>
59#include <utility>
60
63
64// 12 charge points, 15 BetaGamma points, 180 efficiency points for fcp search
65namespace {
66 constexpr int N_Charge = 12;
67 constexpr int N_Velocity = 15;
68 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};
69 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};
70 constexpr double Eff_garfield[N_Charge][N_Velocity] = {
71 {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},
72 {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},
73 {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},
74 {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},
75 {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},
76 {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},
77 {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},
78 {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},
79 {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},
80 {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},
81 {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},
82 {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}};
83 bool
84 validIndex(int idx, int arraySize){
85 return (idx>=0) and (idx<arraySize);
86 }
87} // namespace
88
89using namespace MuonGM;
90namespace {
91 constexpr double SIG_VEL = 4.8;
92}
93
94
95RpcDigitizationTool::RpcDigitizationTool(const std::string& type, const std::string& name, const IInterface* pIID) :
96 PileUpToolBase(type, name, pIID) {}
97
98// member function implementation
99//--------------------------------------------
101 ATH_MSG_DEBUG("RpcDigitizationTool:: in initialize()");
102 ATH_MSG_DEBUG("Configuration RpcDigitizationTool ");
103
104 ATH_MSG_DEBUG("InputObjectName " << m_inputHitCollectionName);
105 ATH_MSG_DEBUG("OutputObjectName " << m_outputDigitCollectionKey.key());
106 ATH_MSG_DEBUG("OutputSDOName " << m_outputSDO_CollectionKey.key());
107 ATH_MSG_DEBUG("WindowLowerOffset " << m_timeWindowLowerOffset);
108 ATH_MSG_DEBUG("WindowUpperOffset " << m_timeWindowUpperOffset);
109 ATH_MSG_DEBUG("DeadTime " << m_deadTime);
110 ATH_MSG_DEBUG("RndmSvc " << m_rndmSvc);
111 ATH_MSG_DEBUG("PatchForRpcTime " << m_patch_for_rpc_time);
112 ATH_MSG_DEBUG("RpcTimeShift " << m_rpc_time_shift);
113 ATH_MSG_DEBUG("RPC_TimeSchema " << m_RPC_TimeSchema);
114 ATH_MSG_DEBUG("RPCSDOareRPCDigits " << m_sdoAreOnlyDigits);
115
116 ATH_MSG_DEBUG("IgnoreRunDependentConfig " << m_ignoreRunDepConfig);
117 ATH_MSG_DEBUG("turnON_efficiency " << m_turnON_efficiency);
118 ATH_MSG_DEBUG("Efficiency_fromCOOL " << m_Efficiency_fromCOOL);
119 ATH_MSG_DEBUG("Efficiency_BIS78_fromCOOL" << m_Efficiency_BIS78_fromCOOL);
120 ATH_MSG_DEBUG("turnON_clustersize " << m_turnON_clustersize);
121 ATH_MSG_DEBUG("ClusterSize_fromCOOL " << m_ClusterSize_fromCOOL);
122 ATH_MSG_DEBUG("ClusterSize_BIS78_fromCOOL" << m_ClusterSize_BIS78_fromCOOL);
123 ATH_MSG_DEBUG("FirstClusterSizeInTail " << m_FirstClusterSizeInTail);
124 ATH_MSG_DEBUG("ClusterSize1_2uncorr " << m_ClusterSize1_2uncorr);
125 ATH_MSG_DEBUG("BOG_BOF_DoubletR2_OFF " << m_BOG_BOF_DoubletR2_OFF);
126 ATH_MSG_DEBUG("CutMaxClusterSize " << m_CutMaxClusterSize);
127 ATH_MSG_DEBUG("CutProjectedTracks " << m_CutProjectedTracks);
128 ATH_MSG_DEBUG("ValidationSetup " << m_validationSetup);
129 ATH_MSG_DEBUG("IncludePileUpTruth " << m_includePileUpTruth);
130 ATH_MSG_DEBUG("VetoPileUpTruthLinks " << m_vetoPileUpTruthLinks);
131
132 ATH_CHECK(m_detMgrKey.initialize());
133 if (m_onlyUseContainerName) { ATH_CHECK(m_mergeSvc.retrieve()); }
134 ATH_CHECK(detStore()->retrieve(m_idHelper));
135 // check the identifiers
136
137 ATH_MSG_INFO("Max Number of RPC Gas Gaps for these Identifiers = " << m_idHelper->gasGapMax());
138
139 // check the input object name
140 if (m_hitsContainerKey.key().empty()) {
141 ATH_MSG_FATAL("Property InputObjectName not set !");
142 return StatusCode::FAILURE;
143 }
145 ATH_MSG_DEBUG("Input objects in container : '" << m_inputHitCollectionName << "'");
146
147 // Initialize ReadHandleKey
148 ATH_CHECK(m_hitsContainerKey.initialize());
149
150 // initialize the output WriteHandleKeys
154 ATH_MSG_DEBUG("Output digits: '" << m_outputDigitCollectionKey.key() << "'");
155
156 // set the configuration based on run1/run2
158
159 ATH_MSG_DEBUG("Ready to read parameters for cluster simulation from file");
160
161 ATH_CHECK(m_rndmSvc.retrieve());
162
163 // fill the taginfo information
165
167
169 // m_turnON_clustersize=false;
170 m_BOF_id = m_idHelper->stationNameIndex("BOF");
171 m_BOG_id = m_idHelper->stationNameIndex("BOG");
172 m_BOS_id = m_idHelper->stationNameIndex("BOS");
173 m_BIL_id = m_idHelper->stationNameIndex("BIL");
174 m_BIS_id = m_idHelper->stationNameIndex("BIS");
176
177 return StatusCode::SUCCESS;
178}
179
181 // TODO This should all be in a conditions Alg
182 // Retrieve geometry config information from the database (RUN1, RUN2, etc...)
183 SmartIF<IGeoModelSvc> geoModel{Gaudi::svcLocator()->service("GeoModelSvc")};
184 if ( !geoModel ) {
185 ATH_MSG_ERROR("Could not locate GeoModelSvc");
186 return StatusCode::FAILURE;
187 }
188
189 // check the DetDescr version
190 std::string atlasVersion = geoModel->atlasVersion();
191
192 SmartIF<IRDBAccessSvc> rdbAccess{Gaudi::svcLocator()->service("RDBAccessSvc")};
193 if ( !rdbAccess ) {
194 ATH_MSG_ERROR("Could not locate RDBAccessSvc");
195 return StatusCode::FAILURE;
196 }
197
198 enum DataPeriod {Unknown, Run1, Run2, Run3, Run4 };
199 DataPeriod run = Unknown;
200
201 std::string configVal = "";
202
203 IRDBRecordset_ptr atlasCommonRec = rdbAccess->getRecordsetPtr("AtlasCommon", atlasVersion, "ATLAS");
204 if (atlasCommonRec->size() == 0) {
205 run = Run1;
206 } else {
207 configVal = (*atlasCommonRec)[0]->getString("CONFIG");
208 ATH_MSG_INFO("From DD Database, Configuration is " << configVal);
209 if (configVal == "RUN1") {
210 run = Run1;
211 } else if (configVal == "RUN2") {
212 run = Run2;
213 } else if (configVal == "RUN3") {
214 run = Run3;
215 } else if (configVal == "RUN4") {
216 run = Run4;
217 }
218 if (run == DataPeriod::Unknown) {
219 ATH_MSG_FATAL("Unexpected value for geometry config read from the database: " << configVal);
220 return StatusCode::FAILURE;
221 }
222 }
223 if (run == Run3 && m_idHelper->gasGapMax() < 3)
224 ATH_MSG_WARNING("Run3, configVal = " << configVal << " and GasGapMax =" << m_idHelper->gasGapMax());
225
226 if (run == Run1)
227 ATH_MSG_INFO("From Geometry DB: MuonSpectrometer configuration is: RUN1 or MuonGeometry = R.06");
228 else if (run == Run2)
229 ATH_MSG_INFO("From Geometry DB: MuonSpectrometer configuration is: RUN2 or MuonGeometry = R.07");
230 else if (run == Run3)
231 ATH_MSG_INFO("From Geometry DB: MuonSpectrometer configuration is: RUN3 or MuonGeometry = R.09");
232 else if (run == Run4)
233 ATH_MSG_INFO("From Geometry DB: MuonSpectrometer configuration is: RUN4 or MuonGeometry = R.10");
234
235 if (m_ignoreRunDepConfig == false) {
237 m_Efficiency_fromCOOL = false;
239 m_RPCInfoFromDb = false;
240 m_kill_deadstrips = false;
241 if (run == Run1) {
242 // m_BOG_BOF_DoubletR2_OFF = true
243 // m_Efficiency_fromCOOL = true
244 // m_ClusterSize_fromCOOL = true
246 if (configVal == "RUN1") { // MC12 setup
249 m_RPCInfoFromDb = true;
250 m_kill_deadstrips = true;
252 }
253 } else {
254 // m_BOG_BOF_DoubletR2_OFF = false # do not turn off at digitization the hits in the dbR=2 chambers in the feet
255 // m_Efficiency_fromCOOL = false # use common average values in python conf.
256 // m_ClusterSize_fromCOOL = false # use common average values in python conf.
258 if (run == Run2) { // MC15c setup
261 m_RPCInfoFromDb = true;
262 m_kill_deadstrips = false;
264 } else {
265 ATH_MSG_INFO("Run3/4: configuration parameter not from COOL");
266 m_Efficiency_fromCOOL = false;
268 m_RPCInfoFromDb = false;
269 m_kill_deadstrips = false;
270 }
271 }
272 ATH_MSG_INFO("RPC Run1/2/3-dependent configuration is enforced");
273 } else {
274 ATH_MSG_WARNING("Run1/2/3-dependent configuration is bypassed; be careful with option settings");
275 }
276
277 ATH_MSG_DEBUG("......RPC Efficiency_fromCOOL " << m_Efficiency_fromCOOL);
278 ATH_MSG_DEBUG("......RPC ClusterSize_fromCOOL " << m_ClusterSize_fromCOOL);
279 ATH_MSG_DEBUG("......RPC BOG_BOF_DoubletR2_OFF " << m_BOG_BOF_DoubletR2_OFF);
280 ATH_MSG_DEBUG("......RPC RPCInfoFromDb " << m_RPCInfoFromDb);
281 ATH_MSG_DEBUG("......RPC KillDeadStrips " << m_kill_deadstrips);
282 ATH_MSG_DEBUG("......RPC CutProjectedTracks " << m_CutProjectedTracks);
283
284
285 return StatusCode::SUCCESS;
286}
287
288template <class CondType>
289StatusCode RpcDigitizationTool::retrieveCondData(const EventContext& ctx,
291 const CondType* & condPtr) const {
292
293 if (key.empty()) {
294 ATH_MSG_DEBUG("No key has been configured for object "<<typeid(CondType).name()<<". Clear pointer");
295 condPtr = nullptr;
296 return StatusCode::SUCCESS;
297 }
298 SG::ReadCondHandle<CondType> readHandle{key, ctx};
299 if (!readHandle.isValid()){
300 ATH_MSG_FATAL("Failed to load conditions object "<<key.fullKey()<<".");
301 return StatusCode::FAILURE;
302 }
303 condPtr = readHandle.cptr();
304 return StatusCode::SUCCESS;
305
306}
307//--------------------------------------------
308StatusCode RpcDigitizationTool::prepareEvent(const EventContext& /*ctx*/, unsigned int) {
309 ATH_MSG_DEBUG("RpcDigitizationTool::in prepareEvent()");
310
311 // John's Hacks START
312 m_RPCHitCollList.clear();
313 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>();
314 // John's Hacks END
315
316 return StatusCode::SUCCESS;
317}
318
319//--------------------------------------------
320StatusCode RpcDigitizationTool::processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) {
321 ATH_MSG_DEBUG("RpcDigitizationTool::in processBunchXing()");
322
324 TimedHitCollList hitCollList;
325
326 if (!(m_mergeSvc->retrieveSubSetEvtData(m_inputHitCollectionName, hitCollList, bunchXing, bSubEvents, eSubEvents).isSuccess()) &&
327 hitCollList.empty()) {
328 ATH_MSG_ERROR("Could not fill TimedHitCollList");
329 return StatusCode::FAILURE;
330 } else {
331 ATH_MSG_VERBOSE(hitCollList.size() << " RPCSimHitCollection with key " << m_inputHitCollectionName << " found");
332 }
333
334 TimedHitCollList::iterator iColl(hitCollList.begin());
335 TimedHitCollList::iterator endColl(hitCollList.end());
336
337 // Iterating over the list of collections
338 for (; iColl != endColl; ++iColl) {
339 RPCSimHitCollection* hitCollPtr = new RPCSimHitCollection(*iColl->second);
340 PileUpTimeEventIndex timeIndex(iColl->first);
341
342 ATH_MSG_DEBUG("RPCSimHitCollection found with " << hitCollPtr->size() << " hits");
343 ATH_MSG_VERBOSE("time index info. time: " << timeIndex.time() << " index: " << timeIndex.index() << " type: " << timeIndex.type());
344
345 m_thpcRPC->insert(timeIndex, hitCollPtr);
346 m_RPCHitCollList.emplace_back(hitCollPtr);
347 }
348
349 return StatusCode::SUCCESS;
350}
351
352//--------------------------------------------
353// Get next event and extract collection of hit collections:
354StatusCode RpcDigitizationTool::getNextEvent(const EventContext& ctx) {
355 ATH_MSG_DEBUG("RpcDigitizationTool::getNextEvent()");
356
357 // initialize pointer
358 m_thpcRPC.reset();
359
360 // get the container(s)
362
363 // In case of single hits container just load the collection using read handles
366 if (!hitCollection.isValid()) {
367 ATH_MSG_ERROR("Could not get RPCSimHitCollection container " << hitCollection.name() << " from store "
368 << hitCollection.store());
369 return StatusCode::FAILURE;
370 }
371
372 // create a new hits collection
373 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>(1);
374 m_thpcRPC->insert(0, hitCollection.cptr());
375 ATH_MSG_DEBUG("RPCSimHitCollection found with " << hitCollection->size() << " hits");
376
377 return StatusCode::SUCCESS;
378 }
379 // this is a list<pair<time_t, DataLink<RPCSimHitCollection> > >
380 TimedHitCollList hitCollList;
381
382 if (!(m_mergeSvc->retrieveSubEvtsData(m_inputHitCollectionName, hitCollList).isSuccess())) {
383 ATH_MSG_ERROR("Could not fill TimedHitCollList");
384 return StatusCode::FAILURE;
385 }
386 if (hitCollList.empty()) {
387 ATH_MSG_ERROR("TimedHitCollList has size 0");
388 return StatusCode::FAILURE;
389 } else {
390 ATH_MSG_DEBUG(hitCollList.size() << " RPCSimHitCollections with key " << m_inputHitCollectionName << " found");
391 }
392
393 // create a new hits collection
394 m_thpcRPC = std::make_unique<TimedHitCollection<RPCSimHit>>();
395 // now merge all collections into one
396 TimedHitCollList::iterator iColl(hitCollList.begin());
397 TimedHitCollList::iterator endColl(hitCollList.end());
398 while (iColl != endColl) {
399 const RPCSimHitCollection* p_collection(iColl->second);
400 m_thpcRPC->insert(iColl->first, p_collection);
401 // if ( m_debug ) ATH_MSG_DEBUG ( "RPCSimHitCollection found with "
402 // << p_collection->size() << " hits" ); // loop on the hit collections
403 ++iColl;
404 }
405 return StatusCode::SUCCESS;
406}
407
408//--------------------------------------------
409StatusCode RpcDigitizationTool::mergeEvent(const EventContext& ctx) {
410 StatusCode status = StatusCode::SUCCESS;
411
412 ATH_MSG_DEBUG("RpcDigitizationTool::in mergeEvent()");
413 // create and record the Digit container in StoreGate
415 ATH_CHECK(digitContainer.record(std::make_unique<RpcDigitContainer>(m_idHelper->module_hash_max())));
416 ATH_MSG_DEBUG("RpcDigitContainer recorded in StoreGate.");
417
418 // Create and record the SDO container in StoreGate
420 ATH_CHECK(sdoContainer.record(std::make_unique<MuonSimDataCollection>()));
421 ATH_MSG_DEBUG("RpcSDOCollection recorded in StoreGate.");
422
424 m_sdo_tmp_map.clear();
426
427 Collections_t collections;
428 status = doDigitization(ctx, collections, sdoContainer.ptr());
429 if (status.isFailure()) { ATH_MSG_ERROR("doDigitization Failed"); }
430 for (size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
431 if (collections[coll_hash]) {
432 ATH_CHECK( digitContainer->addCollection (collections[coll_hash].release(), coll_hash) );
433 }
434 }
435
436 // Clean-up
437 m_RPCHitCollList.clear();
438
439 return status;
440}
441
442//--------------------------------------------
443StatusCode RpcDigitizationTool::processAllSubEvents(const EventContext& ctx) {
444 StatusCode status = StatusCode::SUCCESS;
445
446 // merging of the hit collection in getNextEvent method
447
448 ATH_MSG_DEBUG("RpcDigitizationTool::in digitize()");
449
450 // create and record the Digit container in StoreGate
452 ATH_CHECK(digitContainer.record(std::make_unique<RpcDigitContainer>(m_idHelper->module_hash_max())));
453 ATH_MSG_DEBUG("RpcDigitContainer recorded in StoreGate.");
454
455 // Create and record the SDO container in StoreGate
457 ATH_CHECK(sdoContainer.record(std::make_unique<MuonSimDataCollection>()));
458 ATH_MSG_DEBUG("RpcSDOCollection recorded in StoreGate.");
459
461 m_sdo_tmp_map.clear();
463
464 if (!m_thpcRPC) {
465 status = getNextEvent(ctx);
466 if (StatusCode::FAILURE == status) {
467 ATH_MSG_INFO("There are no RPC hits in this event");
468 return status; // there are no hits in this event
469 }
470 }
471
472 Collections_t collections;
473 ATH_CHECK(doDigitization(ctx, collections, sdoContainer.ptr()));
474 for (size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
475 if (collections[coll_hash]) {
476 ATH_CHECK( digitContainer->addCollection (collections[coll_hash].release(), coll_hash) );
477 }
478 }
479
480 return status;
481}
482
483//--------------------------------------------
484StatusCode RpcDigitizationTool::doDigitization(const EventContext& ctx,
485 Collections_t& collections,
486 MuonSimDataCollection* sdoContainer) {
487 ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this);
488 rngWrapper->setSeed(name(), ctx);
489 CLHEP::HepRandomEngine* rndmEngine = rngWrapper->getEngine(ctx);
490
491 const MuonGM::MuonDetectorManager* detMgr{nullptr};
493
494
495 std::unique_ptr<RPCSimHitCollection> inputSimHitColl{std::make_unique<RPCSimHitCollection>("RPC_Hits")};
496
497
498 // get the iterator pairs for this DetEl
499 // iterate over hits
501
502 // Perform null check on m_thpcRPC
503 if (!m_thpcRPC) {
504 ATH_MSG_ERROR("m_thpcRPC is null");
505 return StatusCode::FAILURE;
506 }
507
508 struct SimDataContent {
509 Identifier channelId{};
510 std::vector<MuonSimData::Deposit> deposits;
511 Amg::Vector3D gpos{Amg::Vector3D::Zero()};
512 double simTime{0.};
513 };
514
515 while (m_thpcRPC->nextDetectorElement(i, e)) {
516 // to store the a single
517
518 std::map<Identifier, SimDataContent> channelSimDataMap;
519
520 // Loop over the hits:
521 while (i != e) {
522 ATH_MSG_DEBUG("RpcDigitizationTool::loop over the hits");
523
524 TimedHitPtr<RPCSimHit> phit(*i++);
525
526 // the hit
527 const RPCSimHit& hit(*phit);
528 // the hit id
529 const int idHit = hit.RPCid();
530 // the global time (G4 time + bunch time)
531 const double globalHitTime{hitTime(phit)};
532 // the G4 time or TOF from IP
533 const double G4Time{hit.globalTime()};
534 // the bunch time
535 const double bunchTime{globalHitTime - hit.globalTime()};
536
537 ATH_MSG_DEBUG("Global time " << globalHitTime << " G4 time " << G4Time << " Bunch time " << bunchTime);
538
539 if (!m_simHitValidKey.empty()) {
540 ATH_MSG_VERBOSE("Validation: globalHitTime, G4Time, BCtime = " << globalHitTime << " " << G4Time << " " << bunchTime);
541 inputSimHitColl->Emplace(idHit, globalHitTime, hit.localPosition(),
542 HepMcParticleLink::getRedirectedLink(phit->particleLink(), phit.eventId(), ctx), // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
543 hit.postLocalPosition(),
544 hit.energyDeposit(), hit.stepLength(), hit.particleEncoding(), hit.kineticEnergy());
545 }
546
547 // convert sim id helper to offline id
548 const std::string stationName = m_muonHelper->GetStationName(idHit);
549 const int stationEta = m_muonHelper->GetZSector(idHit);
550 const int stationPhi = m_muonHelper->GetPhiSector(idHit);
551 const int doubletR = m_muonHelper->GetDoubletR(idHit);
552 const int doubletZ = m_muonHelper->GetDoubletZ(idHit);
553 const int doubletPhi = m_muonHelper->GetDoubletPhi(idHit);
554 int gasGap = m_muonHelper->GetGasGapLayer(idHit);
555
556 if (m_muonHelper->GetMeasuresPhi(idHit)) continue; // Skip phi strip . To be created after efficiency evaluation
557
558
559 bool isValid{false};
560 const Identifier elementID = m_idHelper->elementID(stationName,stationEta,stationPhi,doubletR, isValid);
561 if (!isValid) {
562 ATH_MSG_WARNING("Failed to construct the element ID from "<<stationName
563 <<", stationEta: "<<stationEta<<", stationPhi: "<<stationPhi<<", doubletR: "<<doubletR);
564 continue;
565 }
566 // construct Atlas identifier from components
567 ATH_MSG_DEBUG("creating id for hit in element:"
568 << " stationName " << stationName << " stationEta " << stationEta << " stationPhi " << stationPhi << " doubletR "
569 << doubletR << " doubletZ " << doubletZ << " doubletPhi " << doubletPhi << " gasGap " << gasGap);
570 const Identifier detElId{m_idHelper->channelID(elementID, doubletZ, doubletPhi, 1,0, 1, isValid)};
571 if (!isValid) {
572 continue;
573 }
574 const RpcReadoutElement* reEle = detMgr->getRpcReadoutElement(detElId);
576 if (false && reEle->rotatedRpcModule()) {
577 gasGap = gasGap == 1 ? 2 : 1;
578 }
579
580
581 bool isValidEta{false}, isValidPhi{false};
582 const Identifier idpaneleta = m_idHelper->channelID(elementID, doubletZ, doubletPhi, gasGap, 0, 1, isValidEta);
583 const Identifier idpanelphi = m_idHelper->channelID(elementID, doubletZ, doubletPhi, gasGap, 1, 1, isValidPhi);
584 if (!isValidEta || !isValidPhi) {
585 ATH_MSG_WARNING("Found an invalid identifier "
586 << " stationName " << stationName << " stationEta " << stationEta << " stationPhi " << stationPhi
587 << " doubletR " << doubletR << " doubletZ " << doubletZ << " doubletPhi " << doubletPhi << " gasGap "
588 << gasGap);
589 continue;
590 }
591 // loop on eta and phi to apply correlated efficiency between the two views
592
594 const double tmp_CorrJitter = m_idHelper->stationName(idpaneleta) < 2 ? m_CorrJitter_BIS78 : m_CorrJitter;
596 const double corrtimejitter = tmp_CorrJitter > 0.01 ?
597 CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0., tmp_CorrJitter) : 0.; // correlated jitter
598 // handle here the special case where eta panel is dead => phi strip status (dead or eff.) cannot be resolved;
599 // measured panel eff. will be used in that case and no phi strip killing will happen
600
601
602 // Extrapolate the hit to the gas gap centre located at x=0
603 const Amg::Vector3D hitDir{(hit.postLocalPosition() - hit.localPosition()).unit()};
604 const Amg::Vector3D gapCentre = hit.localPosition() +
605 Amg::intersect<3>(hit.localPosition(), hitDir, Amg::Vector3D::UnitX(), 0).value_or(0) * hitDir;
606
607 std::array<int, 3> pcseta = physicalClusterSize(ctx, reEle, idpaneleta, gapCentre, rndmEngine); // set to one for new algorithms
608 ATH_MSG_VERBOSE("Simulated cluster on eta panel: size/first/last= " << pcseta[0] << "/" << pcseta[1] << "/" << pcseta[2]);
609 std::array<int, 3> pcsphi = physicalClusterSize(ctx, reEle, idpanelphi, gapCentre, rndmEngine); // set to one for new algorithms
610 ATH_MSG_VERBOSE("Simulated cluster on phi panel: size/first/last= " << pcsphi[0] << "/" << pcsphi[1] << "/" << pcsphi[2]);
611
612
613
614 // create Identifiers
615 const Identifier atlasRpcIdeta = m_idHelper->channelID(elementID, doubletZ, doubletPhi, gasGap, 0, pcseta[1], isValidEta);
616 const Identifier atlasRpcIdphi = m_idHelper->channelID(elementID, doubletZ, doubletPhi, gasGap, 1, pcsphi[1], isValidPhi);
617
618 const HepMcParticleLink particleLink = HepMcParticleLink::getRedirectedLink(phit->particleLink(), phit.eventId(), ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
619 const auto [etaStripOn, phiStripOn] = detectionEfficiency(ctx, idpaneleta, idpanelphi, rndmEngine, particleLink);
620 ATH_MSG_DEBUG("SetPhiOn " << phiStripOn << " SetEtaOn " << etaStripOn);
621
622 for (bool imeasphi : {false, true}) {
623 if (!imeasphi && (!etaStripOn || !isValidEta)) continue;
624 if (imeasphi && (!phiStripOn || !isValidPhi)) continue;
625
626
627 // get Identifier and list of clusters for this projection
628 const Identifier& atlasId = !imeasphi ? atlasRpcIdeta : atlasRpcIdphi;
629 std::array<int, 3> pcs{!imeasphi ? pcseta : pcsphi};
630
631 ATH_MSG_DEBUG("SetOn: stationName " << stationName << " stationEta " << stationEta << " stationPhi " << stationPhi
632 << " doubletR " << doubletR << " doubletZ " << doubletZ << " doubletPhi " << doubletPhi
633 << " gasGap " << gasGap << " measphi " << imeasphi);
634
635 // pcs contains the cluster size, the first strip number and the last strip number of the cluster
636 pcs = TurnOnStrips(reEle, std::move(pcs), atlasId);
637 if (pcs[2] < 0){
638 continue;
639 }
640
641 ATH_MSG_DEBUG("Simulated cluster1: size/first/last= " << pcs[0] << "/" << pcs[1] << "/" << pcs[2]);
642
643
644 const Amg::Vector3D pos = fromSimHitToLayer(reEle, atlasId) * hit.localPosition();
645 const Amg::Vector3D gpos = reEle->transform(atlasId) * pos;
646
647 ATH_MSG_VERBOSE(" evt: "<<ctx.eventID().event_number()
648 <<" hit "<<m_idHelper->print_to_string(atlasId)
649 <<" local simHit "<<Amg::toString(hit.localPosition())
650 <<" corrected: "<<Amg::toString(pos)
651 <<" transform: "<<GeoTrf::toString(fromSimHitToLayer(reEle, atlasId))
652 <<" local strip: "<<Amg::toString(reEle->localToGlobalTransf(atlasId).inverse()*reEle->stripPos(atlasId))
653 <<" local strip (II): "<<Amg::toString(reEle->transform(atlasId).inverse()*reEle->stripPos(atlasId))
654 <<" global: "<<Amg::toString(gpos)
655 <<" strip Pos: "<<Amg::toString(reEle->stripPos(atlasId)));
656
657 // Calculate propagation time along readout strip in seconds
658 double proptime = PropagationTime(reEle, atlasId, gpos);
659
660 double tns = G4Time + proptime + corrtimejitter; // the time is in nanoseconds
661 ATH_MSG_VERBOSE("TOF+propagation time " << tns << " /s where proptime " << proptime << "/s");
662
663 double time = tns + bunchTime;
664 ATH_MSG_VERBOSE("final time in ns: BC+TOF+prop " << time << " /ns");
665
666 // pack propagation time along strip, bunch time and local hit position
667 long long int packedMCword = PackMCTruth(proptime, bunchTime, pos.y(), pos.z());
668 //cppcheck-suppress invalidPointerCast
669 double* b = reinterpret_cast<double*>(&packedMCword);
670
672 // create here deposit for MuonSimData
673 // MuonMCData first word is the packing of : proptime, bunchTime, posy, posz
674 // MuonMCData second word is the total hit time: bunchcTime+tof+proptime+correlatedJitter / ns
675 MuonSimData::Deposit deposit(particleLink, MuonMCData((*b), time)); // store tof+strip_propagation+corr.jitter
676 // MuonMCData((*b),G4Time+bunchTime+proptime )); // store tof+strip_propagation
677
678 // Do not store pile-up truth information
680 if (std::abs(hit.particleEncoding()) == 13 || hit.particleEncoding() == 0) {
681 if (channelSimDataMap.find(atlasId) == channelSimDataMap.end()) {
682 SimDataContent& content = channelSimDataMap[atlasId];
683 content.channelId = atlasId;
684 content.deposits.push_back(deposit);
685 content.gpos = reEle->transform(atlasId)*
686 fromSimHitToLayer(reEle,atlasId) * gapCentre;
687 content.simTime = hitTime(phit);
688 ATH_MSG_VERBOSE("adding SDO entry: r " << content.gpos.perp() << " z " << content.gpos.z());
689 }
690 }
691 }
692
693
694 //---------------------------------------------------------------------
695 // construct new digit and store it in the respective digit collection
696 // --------------------------------------------------------------------
697
698 // we create one digit-vector/deposit for each strip in the cluster
699 bool isValid{false};
700 for (int clus = pcs[1]; clus <= pcs[2]; ++clus) {
701 Identifier newId = m_idHelper->channelID(stationName, stationEta, stationPhi, doubletR, doubletZ,
702 doubletPhi, gasGap, imeasphi, clus, isValid);
703 if (!isValid) {
704 ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<< "Channel "<< stationName<<" "<<stationEta<<" "<<stationPhi<<" "<< doubletR<<" "<<doubletZ
705 <<" "<< doubletPhi<<" "<< gasGap <<" "<< imeasphi<<" "<< clus<<" is invalid");
706 continue;
707 }
708
709 if (!m_idHelper->valid(newId)) {
710 if (stationName.find("BI") != std::string::npos) {
711 ATH_MSG_WARNING("Temporary skipping creation of RPC digit for stationName="
712 << stationName << ", eta=" << stationEta << ", phi=" << stationPhi << ", doubletR=" << doubletR
713 << ", doubletZ=" << doubletZ << ", doubletPhi=" << doubletPhi << ", gasGap=" << gasGap
714 << ", measuresPhi=" << imeasphi << ", strip=" << clus << ", cf. ATLASRECTS-6124");
715 return StatusCode::SUCCESS;
716 } else {
717 ATH_MSG_ERROR("Created an invalid id, aborting!");
718 m_idHelper->print(newId);
719 return StatusCode::FAILURE;
720 }
721 }
722
726 // One identifier but several deposits // name m_sdo_tmp_map is wrong call it m_sdo_map
727 if (m_sdo_tmp_map.find(newId) == m_sdo_tmp_map.end()) {
728 std::vector<MuonSimData::Deposit> newdeps;
729 newdeps.push_back(deposit);
730 m_sdo_tmp_map.insert(std::map<Identifier, std::vector<MuonSimData::Deposit>>::value_type(newId, newdeps));
731 } else {
732 m_sdo_tmp_map[newId].push_back(deposit);
733 }
734 } // end for cluster
735 } // loop on eta and phi
736 } // end loop hits
737
738 if (m_muonOnlySDOs) {
739 for (auto it = channelSimDataMap.begin(); it != channelSimDataMap.end(); ++it) {
740 MuonSimData simData(it->second.deposits, 0);
741 simData.setPosition(it->second.gpos);
742 simData.setTime(it->second.simTime);
743 auto insertResult = sdoContainer->insert(std::make_pair(it->first, simData));
744 if (!insertResult.second)
745 ATH_MSG_WARNING("Attention: this sdo is not recorded, since the identifier already exists in the sdoContainer map");
746 }
747 }
748
749 } // end loop detector elements
750
752
753 std::map<Identifier, std::vector<MuonSimData::Deposit>>::iterator map_iter = m_sdo_tmp_map.begin();
754 ATH_MSG_DEBUG("Start the digit map loop");
755
756 for (; map_iter != m_sdo_tmp_map.end(); ++map_iter) {
757 // Identifier
758 const Identifier theId = (*map_iter).first;
759 ATH_MSG_DEBUG("in the map loop: id " << m_idHelper->show_to_string(theId));
760 // Deposit
761 const std::vector<MuonSimData::Deposit> theDeps = (*map_iter).second;
762
763 // store the SDO from the muon
764 MuonSimData::Deposit theMuon; // useful beacuse it sorts the digits in ascending time.
765 std::multimap<double, MuonSimData::Deposit> times; // extract here time info from deposits.
766
767 // loop on the vector deposit
768 for (unsigned int k = 0; k < theDeps.size(); k++) {
769 double time = theDeps[k].second.secondEntry();
770 times.insert(std::multimap<double, MuonSimData::Deposit>::value_type(time, theDeps[k]));
771 }
772
773 // now iterate again over the multimap entries and store digits after dead time applied
774
775 IdContext rpcContext = m_idHelper->module_context(); // work on chamber context
776
777 std::multimap<double, MuonSimData::Deposit>::iterator map_dep_iter = times.begin();
778
779 // loop to suppress digits too close in time (emulate Front-End and CMA dead time)
780 double last_time = -10000; // init to high value
781 for (; map_dep_iter != times.end(); ++map_dep_iter) {
782 double currTime = (*map_dep_iter).first;
783 ATH_MSG_VERBOSE("deposit with time " << currTime);
784
786 // store (before any cut: all G4 hits) in the SDO container
787 // Identifier sdo and digit are the same
788 if (sdoContainer->find(theId) != sdoContainer->end()) // Identifier exist -> increase deposit
789 {
790 std::map<Identifier, MuonSimData>::const_iterator it = sdoContainer->find(theId);
791 std::vector<MuonSimData::Deposit> deps = ((*it).second).getdeposits();
792 deps.push_back((*map_dep_iter).second);
793 } else // Identifier does not exist -> create (Id,deposit)
794 {
795 std::vector<MuonSimData::Deposit> deposits;
796 deposits.push_back((*map_dep_iter).second);
797 std::pair<std::map<Identifier, MuonSimData>::iterator, bool> insertResult =
798 sdoContainer->insert(std::make_pair(theId, MuonSimData(deposits, 0)));
799 if (!insertResult.second)
801 "Attention TEMP: this sdo is not recorded, since the identifier already exists in the sdoContainer map");
802 }
803 }
804 // apply dead time
805 if (std::abs(currTime - last_time) > (m_deadTime)) {
806 ATH_MSG_DEBUG("deposit with time " << currTime << " is distant enough from previous (if any) hit on teh same strip");
807 last_time = (*map_dep_iter).first;
808
809 // first add time jitter to the time:
810 double uncorrjitter = 0;
811 double tmp_UncorrJitter = m_UncorrJitter;
812 if (m_idHelper->stationName(theId) < 2) tmp_UncorrJitter = m_UncorrJitter_BIS78;
813 if (tmp_UncorrJitter > 0.01) uncorrjitter = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0., tmp_UncorrJitter);
814 // Historically patch for the cavern background
815 // Now we subtract TOF from IP to assume full time calibrated detector (t=0 for particle from IP at light speed)
816 // We add a time shift to emulate FE global offset
817
818 const RpcReadoutElement* ele = detMgr->getRpcReadoutElement(theId);
819 Amg::Vector3D posi = ele->stripPos(theId);
820 double tp = m_patch_for_rpc_time ? posi.mag() / Gaudi::Units::c_light : 0.;
821 // Calculate propagation time for a hit at the center of the strip, to be subtructed as well as the nominal TOF
822 double propTimeFromStripCenter = PropagationTime(ele, theId, posi);
823 double newDigit_time = currTime + uncorrjitter + m_rpc_time_shift - tp - propTimeFromStripCenter;
824
825 double digi_ToT = -1.; // Time over threshold, for Narrow-gap RPCs only
826 if (m_idHelper->stationName(theId) < 2) digi_ToT = timeOverThreshold(rndmEngine); //mn
827
828 ATH_MSG_VERBOSE("last_time=currTime " << last_time << " jitter " << uncorrjitter << " TOFcorrection " << tp << " shift "
829 << m_rpc_time_shift << " newDigit_time " << newDigit_time);
830
831 // Apply readout window (sensitive detector time window)
832 bool outsideDigitizationWindow = outsideWindow(newDigit_time);
833 if (outsideDigitizationWindow) {
834 ATH_MSG_VERBOSE("hit outside digitization window - do not produce digits");
835 ATH_MSG_DEBUG("Hit outside time window!!"
836 << " hit time (ns) = " << newDigit_time << " timeWindow = " << m_timeWindowLowerOffset << " / "
838
839 continue;
840 }
841 // ok, let's store this digit
842 // this is an accepted hit to become digit
843 last_time = (*map_dep_iter).first;
844
845 std::unique_ptr<RpcDigit> newDigit = std::make_unique<RpcDigit>(theId, newDigit_time, digi_ToT, false);
846
847 Identifier elemId = m_idHelper->elementID(theId);
848 RpcDigitCollection* digitCollection = nullptr;
849
850 IdentifierHash coll_hash;
851 if (m_idHelper->get_hash(elemId, coll_hash, &rpcContext)) {
852 ATH_MSG_ERROR("Unable to get RPC hash id from RPC Digit collection "
853 << "context begin_index = " << rpcContext.begin_index()
854 << " context end_index = " << rpcContext.end_index() << " the identifier is \n"<<elemId);
855 }
856
857 // make new digit
858 ATH_MSG_DEBUG("Digit Id = " << m_idHelper->show_to_string(theId) << " digit time " << newDigit_time);
859
860 // remember new collection.
861 if (coll_hash >= collections.size()) {
862 collections.resize (coll_hash+1);
863 }
864 digitCollection = collections[coll_hash].get();
865 if (!digitCollection) {
866 collections[coll_hash] = std::make_unique<RpcDigitCollection>(elemId, coll_hash);
867 digitCollection = collections[coll_hash].get();
868 }
869 digitCollection->push_back(std::move(newDigit));
870
872 // put SDO collection in StoreGate
873 if (sdoContainer->find(theId) != sdoContainer->end()) {
874 std::map<Identifier, MuonSimData>::const_iterator it = sdoContainer->find(theId);
875 std::vector<MuonSimData::Deposit> deps = ((*it).second).getdeposits();
876 deps.push_back((*map_dep_iter).second);
877 } else {
878 std::vector<MuonSimData::Deposit> deposits;
879 deposits.push_back((*map_dep_iter).second);
880 std::pair<std::map<Identifier, MuonSimData>::iterator, bool> insertResult =
881 sdoContainer->insert(std::make_pair(theId, MuonSimData(deposits, 0)));
882 if (!insertResult.second)
884 "Attention: this sdo is not recorded, since teh identifier already exists in the sdoContainer map");
885 }
886 }
887
888 } else
889 ATH_MSG_DEBUG("discarding digit due to dead time: " << (*map_dep_iter).first << " " << last_time);
890 }
891
892 } // loop to suppress digits too close in time ended
893
894 // reset the pointer if it not null
895 m_thpcRPC.reset();
896 if (!m_simHitValidKey.empty()) {
898 ATH_CHECK(validHandle.record(std::move(inputSimHitColl)));
899 }
900
901 return StatusCode::SUCCESS;
902}
904 const Identifier& layerId) const {
905
906 Amg::Vector3D lGasGapPos = reEle->localGasGapPos(layerId);
907 if (reEle->NphiStripPanels() != reEle->nGasGapPerLay()) {
908 lGasGapPos.y() =0.;
909 }
910
914 const bool flip = reEle->numberOfLayers() == 2 &&
915 (m_idHelper->gasGap(layerId) == 2) != reEle->rotatedRpcModule();
916 const Amg::Transform3D fromHitToGap{reEle->transform(layerId).inverse() *
917 reEle->absTransform() * Amg::getTranslate3D(lGasGapPos) *
918 (flip ? Amg::getRotateY3D(180.*Gaudi::Units::deg) : Amg::Transform3D::Identity())};
919 ATH_MSG_VERBOSE("Transformation to go from hit to gap restframe "<<m_idHelper->print_to_string(layerId)
920 <<" "<<Amg::toString(fromHitToGap));
921 return fromHitToGap;
922}
923
924//--------------------------------------------
925std::array<int, 3> RpcDigitizationTool::physicalClusterSize(const EventContext& ctx,
926 const RpcReadoutElement* ele,
927 const Identifier& id,
928 const Amg::Vector3D& gapCentre,
929 CLHEP::HepRandomEngine* rndmEngine) const {
930
931
932 std::array<int, 3> result{};
933
934 const Amg::Vector3D position = fromSimHitToLayer(ele, id) * gapCentre;
935
936 const int doubletPhi = m_idHelper->doubletPhi(id);
937 const int gasGap = m_idHelper->gasGap(id);
938 const bool measuresPhi = m_idHelper->measuresPhi(id);
939 const double pitch= ele->StripPitch(measuresPhi);
940
941
942 const int nstrip = ele->stripNumber(position.block<2,1>(0,0), id);
943 const int numStrips = ele->Nstrips(measuresPhi);
944
945 result[1] = nstrip;
946 result[2] = nstrip;
947
948 if (nstrip < 1 || nstrip > numStrips) {
949 return make_array<int, 3>(-1);
950 }
951 const Amg::Vector3D locStripPos = ele->transform(id).inverse()*ele->stripPos(doubletPhi, gasGap, measuresPhi, nstrip);
952 float xstripnorm = (locStripPos -position).x() / pitch ;
953 result[0] = determineClusterSize(ctx, id, xstripnorm, rndmEngine);
954
955 //
956
957
958 if (m_turnON_clustersize == false) result[0] = 1;
959
960 return result;
961}
962
963//--------------------------------------------
965 std::array<int, 3>&& pcs,
966 const Identifier& id) const {
967
968
969 const int nstrips = ele->Nstrips(m_idHelper->measuresPhi(id));
970
971 if (pcs[0] == -2) {
972 pcs[1] = pcs[2] - 1;
973 } else if (pcs[0] == 2) {
974 pcs[2] = pcs[1] + 1;
975 } else if (pcs[0] > 2) {
976 pcs[1] = pcs[1] - pcs[0] / 2;
977 if (fmod(pcs[0], 2) == 0) pcs[1] = pcs[1] + 1;
978 pcs[2] = pcs[1] + pcs[0] - 1;
979 } else if (pcs[0] < -2) {
980 pcs[1] = pcs[1] + pcs[0] / 2;
981 pcs[2] = pcs[1] - pcs[0] - 1;
982 }
983
984 // cut the clusters at the beginning and at the end of the chamber
985
986 pcs[1] = std::clamp(pcs[1], 1, nstrips);
987 pcs[2] = std::clamp(pcs[2], 1, nstrips);
988
989 pcs[0] = pcs[2] - pcs[1] + 1;
990
991 return pcs;
992}
993
994//--------------------------------------------
996 const Identifier& id,
997 const Amg::Vector3D& globPos) const {
998
999 double distance{0.};
1000 if (m_idHelper->measuresPhi(id)) {
1001 distance = ele->distanceToPhiReadout(globPos);
1002 } else {
1003 distance = ele->distanceToEtaReadout(globPos);
1004 }
1005
1006 // distance in mm, SIG_VEL in ns/m
1007 return std::abs(distance * SIG_VEL * 1.e-3);
1008}
1009
1010//--------------------------------------------
1011long long int RpcDigitizationTool::PackMCTruth(float proptime, float bctime, float posy, float posz) const {
1012 // start with proptime: it is usually ~ns. It comes in ns. We express it in ns/10. use only 8 bits
1013 if (proptime < 0) {
1014 ATH_MSG_WARNING("A poblem: packing a propagation time <0 " << proptime << " redefine it as 0");
1015 proptime = 0.;
1016 }
1017 long long int new_proptime = int(proptime * 10) & 0xff;
1018
1019 // now tof. it is ~100ns. comes in ns. express it in ns/10. 16 bits needed (0-32768)
1020 // now BC time: it is ~100ns. comes in ns. express it in ns/10. 16 bits needed (0-32768)
1021 // can be negative (=> add 300 ns)
1022
1023 long long int new_bctime = int((bctime + 300.) * 10.) & 0xffff;
1024
1025 // posy: ~1000mm comes in mm, write it in mm*10. need 16 bits (0-32768)
1026 // can be negative (=>add 1500 mm)
1027
1028 long long int new_posy = int((posy + 1500.) * 10.) & 0xffff;
1029
1030 // posz: ~1000mm comes in mm, write it in mm*10. need 16 bits (0-32768)
1031 // can be negative (=>add 1500 mm)
1032
1033 long long int new_posz = int((posz + 1500.) * 10.) & 0xffff;
1034
1035 return (new_proptime + (new_bctime << 8) + (new_posy << 24) + (new_posz << 40));
1036}
1037
1038//--------------------------------------------
1039void RpcDigitizationTool::UnPackMCTruth(double theWord, float& proptime, float& bctime, float& posy, float& posz) {
1040 // int64_t is just a shorter way of writing long long int
1041 using Repacker = union
1042
1043 {
1044 double dWord;
1045
1046 int64_t iWord;
1047 };
1048 Repacker MCTruth;
1049 MCTruth.dWord = theWord;
1050 proptime = ((MCTruth.iWord) & 0x00000000000000ffLL) / 10.;
1051 bctime = (((MCTruth.iWord) & 0x0000000000ffff00LL) >> 8) / 10.;
1052 posy = (((MCTruth.iWord) & 0x000000ffff000000LL) >> 24) / 10.;
1053 posz = (((MCTruth.iWord) & 0x00ffff0000000000LL) >> 40) / 10.;
1054
1055 //
1056 bctime = bctime - 300.;
1057 posy = posy - 1500.;
1058 posz = posz - 1500.;
1059}
1060
1061//--------------------------------------------
1063 // get TagInfoMgr
1064 SmartIF<ITagInfoMgr> tagInfoMgr{Gaudi::svcLocator()->service("TagInfoMgr")}; // Tag Info Manager
1065 if (!tagInfoMgr) { return StatusCode::FAILURE; }
1066
1067 std::string RpctimeSchema = "";
1068 std::stringstream RpctimeShift;
1069 RpctimeShift << (int)m_rpc_time_shift;
1070
1072 RpctimeSchema = "Datalike_TOFoff_TimeShift" + RpctimeShift.str() + "nsec";
1073 } else {
1074 RpctimeSchema = "G4like_TOFon_TimeShift" + RpctimeShift.str() + "nsec";
1075 }
1076
1077 StatusCode sc = tagInfoMgr->addTag(m_RPC_TimeSchema, RpctimeSchema);
1078
1079 if (sc.isFailure()) {
1080 ATH_MSG_WARNING(m_RPC_TimeSchema << " " << RpctimeSchema << " not added to TagInfo ");
1081 return sc;
1082 }
1083
1084 ATH_MSG_DEBUG(m_RPC_TimeSchema << " " << RpctimeSchema << " added to TagInfo ");
1085
1086 return StatusCode::SUCCESS;
1087}
1088
1089
1090//--------------------------------------------
1091std::pair<bool,bool> RpcDigitizationTool::detectionEfficiency(const EventContext& ctx,
1092 const Identifier& IdEta,
1093 const Identifier& IdPhi,
1094 CLHEP::HepRandomEngine* rndmEngine,
1095 const HepMcParticleLink& trkParticle) const {
1096
1097
1098
1099 ATH_MSG_DEBUG("RpcDigitizationTool::in DetectionEfficiency");
1100
1101 ATH_MSG_DEBUG("EtaPanelId to look for Eff is " << m_idHelper->show_to_string(IdEta));
1102 ATH_MSG_DEBUG("PhiPanelId to look for Eff is " << m_idHelper->show_to_string(IdPhi));
1103
1104
1105 // dead spacers are not simulated in GEANT4 => their effect must be emulated in the digitizer as an effective max. efficiency = 99%
1106 // (spacers are 1x1cm^2 over a grid of 10x10cm^2 =? geometrical ineff. introduced is 1% for normal incidence)
1107 float maxGeomEff{0.99}, PhiAndEtaEff{0.99}, OnlyEtaEff{0.f}, OnlyPhiEff{0.f};
1108
1109 // 2=BML,3=BMS,4=BOL,5=BOS,8=BMF,9=BOF,10=BOG
1110 int stationName = m_idHelper->stationName(IdEta);
1111 int stationEta = m_idHelper->stationEta(IdEta);
1112 int doubletR = m_idHelper->doubletR(IdEta);
1113
1114 // remove feet extension. driven by joboption
1115 if (m_BOG_BOF_DoubletR2_OFF && (stationName == m_BOF_id || stationName == m_BOG_id) && doubletR == 2) {
1116 return std::make_pair(false, false);
1117 }
1118
1119
1120 if (!m_turnON_efficiency) {
1121 return std::make_pair(true, true);
1122 }
1123 bool etaStripOn{true}, phiStripOn{true};
1124
1125 // int stripetadead = 0 ; // not used
1126 // int stripphidead = 0 ; // not used
1127
1128 unsigned int index = stationName - 2;
1129 // BML and BMS, BOL and BOS come first (stationName= 2 and 3, 4 and 5 -> index 0-3)
1130 if (stationName > 5 && stationName < 50) index = index - 2;
1131 // BMF, BOF and BOG are 8,9,10 => must be 4,5 and 6
1132 else if (stationName > 50)
1133 index = index - 44;
1134 // BME and BOE 53 and 54 are at indices 7 and 8
1135
1136 if (!m_Efficiency_fromCOOL && stationName >= 2) {
1137 if (index > m_PhiAndEtaEff_A.size() || index > m_OnlyEtaEff_A.size() || index > m_OnlyPhiEff_A.size()) {
1138 THROW_EXCEPTION("Index out of array in Detection Efficiency SideA " << index << " stationName = " << stationName);
1139 }
1140
1141 PhiAndEtaEff = m_PhiAndEtaEff_A[index];
1142 OnlyEtaEff = m_OnlyEtaEff_A[index];
1143 OnlyPhiEff = m_OnlyPhiEff_A[index];
1144
1145 if (stationEta < 0) {
1146 if (index > m_PhiAndEtaEff_C.size() || index > m_OnlyEtaEff_C.size() || index > m_OnlyPhiEff_C.size()) {
1147 THROW_EXCEPTION("Index out of array in Detection Efficiency SideC " << index << " stationName = " << stationName);
1148 }
1149 PhiAndEtaEff = m_PhiAndEtaEff_C[index];
1150 OnlyEtaEff = m_OnlyEtaEff_C[index];
1151 OnlyPhiEff = m_OnlyPhiEff_C[index];
1152 }
1153 } else if (stationName < 2 && (!m_Efficiency_fromCOOL || !m_Efficiency_BIS78_fromCOOL)) { // BIS
1154 PhiAndEtaEff = m_PhiAndEtaEff_BIS78;
1155 OnlyEtaEff = m_OnlyEtaEff_BIS78;
1156 OnlyPhiEff = m_OnlyPhiEff_BIS78;
1157 } else { // Efficiency from Cool
1158
1159 const RpcCondDbData* readCdo{nullptr};
1160 if(!retrieveCondData(ctx, m_readKey, readCdo).isSuccess()){
1161 THROW_EXCEPTION("Failed to retrieve conditions object");
1162 }
1163
1164 ATH_MSG_DEBUG("Efficiencies and cluster size + dead strips will be extracted from COOL");
1165
1166 double FracDeadStripEta{0.}, FracDeadStripPhi{0.};
1167 double EtaPanelEfficiency{1.}, PhiPanelEfficiency{1.}, GapEfficiency{1.};
1168 int RPC_ProjectedTracksEta = 0;
1169
1170 std::optional<double> fracDeadStripEtaFromCOOL = readCdo->getFracDeadStrip(IdEta);
1171 std::optional<double> fracDeadStripPhiFromCOOL = readCdo->getFracDeadStrip(IdPhi);
1172
1173 bool noEntryInDb = !fracDeadStripEtaFromCOOL || !fracDeadStripPhiFromCOOL;
1174
1175 FracDeadStripEta = fracDeadStripEtaFromCOOL.value_or(0.);
1176 FracDeadStripPhi = fracDeadStripPhiFromCOOL.value_or(0.);
1177 RPC_ProjectedTracksEta = readCdo->getProjectedTrack(IdEta).value_or(0);
1178
1179 EtaPanelEfficiency = readCdo->getEfficiency(IdEta).value_or(1.);
1180 PhiPanelEfficiency = readCdo->getEfficiency(IdPhi).value_or(1.);
1181 GapEfficiency = readCdo->getGapEfficiency(IdEta).value_or(1.);
1182
1183 if (std::abs(FracDeadStripEta - 1.) < 0.001) {
1184 ATH_MSG_DEBUG("Watch out: SPECIAL CASE: Read from Cool: FracDeadStripEta/Phi "
1185 << FracDeadStripEta << "/" << FracDeadStripPhi << " RPC_ProjectedTracksEta " << RPC_ProjectedTracksEta
1186 << " Eta/PhiPanelEfficiency " << EtaPanelEfficiency << "/" << PhiPanelEfficiency << " gapEff " << GapEfficiency
1187 << " for gas gap " << m_idHelper->show_to_string(IdEta) << " id " << IdEta.get_identifier32().get_compact());
1188 // dead eta panel => cannot determine the strip status for phi strips
1189 // FracDeadStripPhi must be reset to 0. and undefinedPhiStripStatus = true
1190 FracDeadStripPhi = 0.;
1191 ATH_MSG_VERBOSE("Watch out: SPECIAL CASE: Resetting FracDeadStripPhi " << FracDeadStripPhi << " ignoring phi dead strips ");
1192 }
1193
1194 // special test
1195 // here redefining the efficiencies:
1196 // EtaPanelEfficiency = 0.92;
1197 // PhiPanelEfficiency = 0.85;
1198 // GapEfficiency = 0.97;
1199 bool changing = false;
1200 ATH_MSG_DEBUG("Read from Cool: FracDeadStripEta/Phi " << FracDeadStripEta << "/" << FracDeadStripPhi << " RPC_ProjectedTracksEta "
1201 << RPC_ProjectedTracksEta << " Eta/PhiPanelEfficiency " << EtaPanelEfficiency
1202 << "/" << PhiPanelEfficiency << " gapEff " << GapEfficiency);
1203 // if ((1.-FracDeadStripEta)<EtaPanelEfficiency)
1204 if ((maxGeomEff - FracDeadStripEta) - EtaPanelEfficiency < -0.011) {
1205 ATH_MSG_DEBUG("Ineff. from dead strips on Eta Panel larger that measured efficiency: deadFrac="
1206 << FracDeadStripEta << " Panel Eff=" << EtaPanelEfficiency << " for Panel " << m_idHelper->show_to_string(IdEta));
1207 ATH_MSG_DEBUG("... see the corresponding report from RpcDetectorStatusDbTool");
1208 // EtaPanelEfficiency = 1.-FracDeadStripEta;
1209 EtaPanelEfficiency = maxGeomEff - FracDeadStripEta;
1210 changing = true;
1211 }
1212 // if ((1.-FracDeadStripPhi)<PhiPanelEfficiency)
1213 if ((maxGeomEff - FracDeadStripPhi) - PhiPanelEfficiency < -0.011) {
1214 ATH_MSG_DEBUG("Ineff. from dead strips on Phi Panel larger that measured efficiency: deadFrac="
1215 << FracDeadStripPhi << " Panel Eff=" << PhiPanelEfficiency << " for Panel " << m_idHelper->show_to_string(IdPhi));
1216 ATH_MSG_DEBUG("... see the corresponding report among the warnings of RpcDetectorStatusDbTool");
1217 // PhiPanelEfficiency = 1.-FracDeadStripPhi;
1218 PhiPanelEfficiency = maxGeomEff - FracDeadStripPhi;
1219 changing = true;
1220 }
1221 // if ((1.-FracDeadStripEta*FracDeadStripPhi)<GapEfficiency)
1222 if ((maxGeomEff - FracDeadStripEta * FracDeadStripPhi) - GapEfficiency < -0.011) {
1223 ATH_MSG_DEBUG("Ineff. from dead strips on Eta/Phi Panels larger that measured EtaORPhi efficiency: deadFrac="
1224 << FracDeadStripEta * FracDeadStripPhi << " EtaORPhi Eff=" << GapEfficiency << " for GasGap "
1225 << m_idHelper->show_to_string(IdEta));
1226 ATH_MSG_DEBUG("... see the corresponding report among the warnings of RpcDetectorStatusDbTool");
1227 // GapEfficiency = 1.-FracDeadStripEta*FracDeadStripPhi;
1228 GapEfficiency = maxGeomEff - FracDeadStripEta * FracDeadStripPhi;
1229 changing = true;
1230 }
1231 if (changing)
1232 ATH_MSG_DEBUG("Rinormalized Values from Cool: FracDeadStripEta/Phi "
1233 << FracDeadStripEta << "/" << FracDeadStripPhi << " RPC_ProjectedTracksEta " << RPC_ProjectedTracksEta
1234 << " Eta/PhiPanelEfficiency " << EtaPanelEfficiency << "/" << PhiPanelEfficiency << " gapEff " << GapEfficiency);
1235
1236 // gabriele //..stefania - if there are dead strips renormalize the eff. to the active area
1237 if (m_kill_deadstrips) {
1238 if ((FracDeadStripEta > 0.0 && FracDeadStripEta < 1.0) || (FracDeadStripPhi > 0.0 && FracDeadStripPhi < 1.0) || (noEntryInDb)) {
1239 EtaPanelEfficiency = EtaPanelEfficiency / (maxGeomEff - FracDeadStripEta);
1240 PhiPanelEfficiency = PhiPanelEfficiency / (maxGeomEff - FracDeadStripPhi);
1241 GapEfficiency = GapEfficiency / (maxGeomEff - FracDeadStripEta * FracDeadStripPhi);
1242
1243 if (EtaPanelEfficiency > maxGeomEff) EtaPanelEfficiency = maxGeomEff;
1244 if (PhiPanelEfficiency > maxGeomEff) PhiPanelEfficiency = maxGeomEff;
1245 if (GapEfficiency > maxGeomEff) GapEfficiency = maxGeomEff;
1246
1247 if (EtaPanelEfficiency > GapEfficiency) GapEfficiency = EtaPanelEfficiency;
1248 if (PhiPanelEfficiency > GapEfficiency) GapEfficiency = PhiPanelEfficiency;
1249 ATH_MSG_DEBUG("Eff Redefined (to correct for deadfrac): FracDeadStripEta/Phi "
1250 << " Eta/PhiPanelEfficiency " << EtaPanelEfficiency << "/" << PhiPanelEfficiency << " gapEff "
1251 << GapEfficiency);
1252 }
1253 }
1254
1255 // values from COOLDB (eventually overwritten later)
1256 PhiAndEtaEff = float(EtaPanelEfficiency + PhiPanelEfficiency - GapEfficiency);
1257 if (PhiAndEtaEff < 0.) PhiAndEtaEff = 0.;
1258 OnlyEtaEff = float(EtaPanelEfficiency - PhiAndEtaEff);
1259 if (OnlyEtaEff < 0.) OnlyEtaEff = 0.;
1260 OnlyPhiEff = float(PhiPanelEfficiency - PhiAndEtaEff);
1261 if (OnlyPhiEff < 0.) OnlyPhiEff = 0.;
1262
1263 // special patch to be true only when m_Efficiency_fromCOOL=true and /RPC/DQMF/ELEMENT_STATUS tag is
1264 // RPCDQMFElementStatus_2012_Jaunuary_26
1265 bool applySpecialPatch = false;
1267 if (m_idHelper->stationName(IdEta) == 3)
1268 {
1269 if (std::abs(m_idHelper->stationEta(IdEta)) == 6 && m_idHelper->doubletR(IdEta) == 1 &&
1270 m_idHelper->doubletZ(IdEta) == 2 && m_idHelper->doubletPhi(IdEta) == 1) {
1271 applySpecialPatch = true;
1273 "Applying special patch for BMS at |eta|=6 lowPt plane -dbbZ=2 and dbPhi=1 ... will use default eff. for Id "
1274 << m_idHelper->show_to_string(IdEta));
1276 "Applying special patch: THIS HAS TO BE DONE IF /RPC/DQMF/ELEMENT_STATUS tag is "
1277 "RPCDQMFElementStatus_2012_Jaunuary_2");
1278 }
1279 }
1280 }
1281
1282 // if projected tracks number too low or inconsistent values get efficiencies from joboption and overwrite previous values
1283 if (applySpecialPatch || RPC_ProjectedTracksEta < m_CutProjectedTracks || RPC_ProjectedTracksEta > 10000000 ||
1284 EtaPanelEfficiency > 1 || EtaPanelEfficiency < 0 || PhiPanelEfficiency > 1 || PhiPanelEfficiency < 0 || GapEfficiency > 1 ||
1285 GapEfficiency < 0) {
1286 if (index > m_PhiAndEtaEff_A.size() || index > m_OnlyEtaEff_A.size() || index > m_OnlyPhiEff_A.size()) {
1287 THROW_EXCEPTION("Index out of array in Detection Efficiency SideA COOLDB" << index << " stationName = " << stationName);
1288 }
1289 if (RPC_ProjectedTracksEta < m_CutProjectedTracks)
1290 ATH_MSG_DEBUG("# of proj tracks = " << RPC_ProjectedTracksEta << " < cut = " << m_CutProjectedTracks
1291 << " resetting eff. from cool with default(python) values ");
1292
1293 PhiAndEtaEff = m_PhiAndEtaEff_A[index];
1294 OnlyEtaEff = m_OnlyEtaEff_A[index];
1295 OnlyPhiEff = m_OnlyPhiEff_A[index];
1296
1297 if (stationEta < 0) {
1298 if (index > m_PhiAndEtaEff_C.size() || index > m_OnlyEtaEff_C.size() || index > m_OnlyPhiEff_C.size()) {
1299 THROW_EXCEPTION("Index out of array in Detection Efficiency SideC COOLDB" << index << " stationName = " << stationName);
1300 }
1301 PhiAndEtaEff = m_PhiAndEtaEff_C[index];
1302 OnlyEtaEff = m_OnlyEtaEff_C[index];
1303 OnlyPhiEff = m_OnlyPhiEff_C[index];
1304 }
1305
1306 // if (m_applyEffThreshold) {
1307 // gabriele Set efficiency from dead strip fraction instead of nominal value
1308 float effgap = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1309 float s_EtaPanelEfficiency = 1. - FracDeadStripEta;
1310 float s_PhiPanelEfficiency = 1. - FracDeadStripPhi;
1311 float s_PhiAndEtaEff = s_EtaPanelEfficiency * s_PhiPanelEfficiency / effgap;
1312 if (s_PhiAndEtaEff < PhiAndEtaEff) PhiAndEtaEff = s_PhiAndEtaEff;
1313 float s_OnlyEtaEff = s_EtaPanelEfficiency - PhiAndEtaEff;
1314 float s_OnlyPhiEff = s_PhiPanelEfficiency - PhiAndEtaEff;
1315
1316 if (s_OnlyEtaEff < OnlyEtaEff) OnlyEtaEff = s_OnlyEtaEff;
1317 if (s_OnlyPhiEff < OnlyPhiEff) OnlyPhiEff = s_OnlyPhiEff;
1318 // }
1319 }
1320
1321 float VolEff = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1322 if (VolEff > maxGeomEff) {
1323 PhiAndEtaEff = (PhiAndEtaEff / VolEff) * maxGeomEff;
1324 OnlyEtaEff = (OnlyEtaEff / VolEff) * maxGeomEff;
1325 OnlyPhiEff = (OnlyPhiEff / VolEff) * maxGeomEff;
1326 }
1327
1328 } // End eff from COOL
1329
1330 // Efficiency correction factor for fractional-charged particles(added by Quanyin Li: quli@cern.ch)
1331 // link to truth particles and calculate the charge and betagamma
1332 HepMC::ConstGenParticlePtr genparticle = trkParticle.cptr();
1333 if (genparticle) {
1334 // only apply efficiency correction to fractional-charged particles based on pdgId betagamma
1335 if (MC::isGenericMultichargedParticle(genparticle)) {
1336 const double eff_sf = FCPEfficiency(genparticle);
1337 // Apply scale factor to the 3 Eff.
1338 PhiAndEtaEff = PhiAndEtaEff * eff_sf;
1339 OnlyEtaEff = OnlyEtaEff * eff_sf;
1340 OnlyPhiEff = OnlyPhiEff * eff_sf;
1341 }
1342 }
1343
1344 float I0 = PhiAndEtaEff;
1345 float I1 = PhiAndEtaEff + OnlyEtaEff;
1346 float ITot = PhiAndEtaEff + OnlyEtaEff + OnlyPhiEff;
1347
1348 float GapEff = ITot ;
1349 float PhiEff = PhiAndEtaEff + OnlyPhiEff;
1350 float EtaEff = PhiAndEtaEff + OnlyEtaEff;
1351
1352 ATH_MSG_DEBUG("DetectionEfficiency: Final Efficiency Values applied for "
1353 << m_idHelper->show_to_string(IdEta) << " are " << PhiAndEtaEff << "=PhiAndEtaEff " << OnlyEtaEff
1354 << "=OnlyEtaEff " << OnlyPhiEff << "=OnlyPhiEff " << GapEff << "=GapEff " << EtaEff << "=EtaEff " << PhiEff
1355 << "=PhiEff ");
1356
1357 float rndmEff = CLHEP::RandFlat::shoot(rndmEngine, 1);
1358
1359 if (rndmEff < I0) {
1360 phiStripOn = true;
1361 etaStripOn = true;
1362 } else if ((I0 <= rndmEff) && (rndmEff < I1)) {
1363 phiStripOn = false;
1364 etaStripOn = true;
1365 } else if ((I1 <= rndmEff) && (rndmEff <= ITot)) {
1366 phiStripOn = true;
1367 etaStripOn = false;
1368 } else {
1369 phiStripOn = false;
1370 etaStripOn = false;
1371 }
1372
1373 return std::make_pair(etaStripOn, phiStripOn);
1374}
1375
1376//--------------------------------------------
1378 const Identifier& idRpcStrip,
1379 double xstripnorm,
1380 CLHEP::HepRandomEngine* rndmEngine) const {
1381 ATH_MSG_DEBUG("RpcDigitizationTool::in determineClusterSize");
1382
1383 ATH_MSG_DEBUG("Digit Id = " << m_idHelper->show_to_string(idRpcStrip));
1384
1385 int ClusterSize = 1;
1386
1387 double FracClusterSize1{1.}, FracClusterSize2{0.}, MeanClusterSize{1.},
1388 FracClusterSizeTail{0.}, MeanClusterSizeTail{1.},
1389 FracClusterSize2norm{0.};
1390
1391 // 2=BML,3=BMS,4=BOL,5=BOS,8=BMF,9=BOF,10=BOG
1392 int stationName = m_idHelper->stationName(idRpcStrip);
1393 int stationEta = m_idHelper->stationEta(idRpcStrip);
1394 int measuresPhi = m_idHelper->measuresPhi(idRpcStrip);
1395
1396 unsigned int index = stationName - 2;
1397 // BML and BMS, BOL and BOS come first (stationName= 2 and 3, 4 and 5 -> index 0-3)
1398 if (stationName > 5 && stationName < 50) index = index - 2;
1399 // BMF, BOF and BOG are 8,9,10 => must be 4,5 and 6
1400 else if (stationName > 50)
1401 index = index - 44;
1402 // BME and BOE 53 and 54 are at indices 7 and 8
1403
1404 if (!m_ClusterSize_fromCOOL && stationName >= 2) {
1405 index += m_FracClusterSize1_A.size() / 2 * measuresPhi;
1406 if (index >= m_FracClusterSize1_A.size() ||
1407 index >= m_FracClusterSize2_A.size() ||
1408 index >= m_FracClusterSizeTail_A.size() ||
1409 index >= m_MeanClusterSizeTail_A.size()) {
1410 ATH_MSG_ERROR("Index out of array in determineClusterSize SideA " << index << " statName " << stationName);
1411 return 1;
1412 }
1413 FracClusterSize1 = m_FracClusterSize1_A[index];
1414 FracClusterSize2 = m_FracClusterSize2_A[index];
1415 FracClusterSizeTail = m_FracClusterSizeTail_A[index];
1416 MeanClusterSizeTail = m_MeanClusterSizeTail_A[index];
1417
1418 if (stationEta < 0) {
1419 index += m_FracClusterSize1_C.size() / 2 * measuresPhi - m_FracClusterSize1_A.size() / 2 * measuresPhi;
1420 if (index >= m_FracClusterSize1_C.size() ||
1421 index >= m_FracClusterSize2_C.size() ||
1422 index >= m_FracClusterSizeTail_C.size() ||
1423 index >= m_MeanClusterSizeTail_C.size()) {
1424 ATH_MSG_ERROR("Index out of array in determineClusterSize SideC " << index << " statName " << stationName);
1425 return 1;
1426 }
1427 FracClusterSize1 = m_FracClusterSize1_C[index];
1428 FracClusterSize2 = m_FracClusterSize2_C[index];
1429 FracClusterSizeTail = m_FracClusterSizeTail_C[index];
1430 MeanClusterSizeTail = m_MeanClusterSizeTail_C[index];
1431 }
1432 } else if (stationName < 2 && (!m_ClusterSize_fromCOOL || !m_ClusterSize_BIS78_fromCOOL)) { // BIS78
1433 FracClusterSize1 = m_FracClusterSize1_BIS78;
1434 FracClusterSize2 = m_FracClusterSize2_BIS78;
1435 FracClusterSizeTail = m_FracClusterSizeTail_BIS78;
1436 MeanClusterSizeTail = m_MeanClusterSizeTail_BIS78;
1437 } else { // Cluster size from COOL
1438 const RpcCondDbData* readCdo{nullptr};
1439 retrieveCondData(ctx, m_readKey, readCdo).ignore();
1440
1441 Identifier Id = m_idHelper->panelID(idRpcStrip);
1442
1443 int RPC_ProjectedTracks = readCdo->getProjectedTrack(Id).value_or(0);
1444 FracClusterSize1 = readCdo->getFracClusterSize1(Id).value_or(1.);
1445 FracClusterSize2 = readCdo->getFracClusterSize2(Id).value_or(0.);
1446 MeanClusterSize = readCdo->getMeanClusterSize(Id).value_or(1.);
1447
1448
1449 ATH_MSG_DEBUG("FracClusterSize1 and 2 " << FracClusterSize1 << " " << FracClusterSize2);
1450
1451 FracClusterSizeTail = 1. - FracClusterSize1 - FracClusterSize2;
1452
1453 MeanClusterSizeTail = MeanClusterSize - FracClusterSize1 - 2 * FracClusterSize2;
1454
1455 ATH_MSG_DEBUG("MeanClusterSizeTail and FracClusterSizeTail " << MeanClusterSizeTail << " " << FracClusterSizeTail);
1456
1457 // if clustersize have anomalous values set to the average cluster size from joboption
1458 if (RPC_ProjectedTracks < m_CutProjectedTracks || RPC_ProjectedTracks > 10000000 || MeanClusterSize > m_CutMaxClusterSize ||
1459 MeanClusterSize <= 1 || FracClusterSizeTail < 0 || FracClusterSize1 < 0 || FracClusterSize2 < 0 || FracClusterSizeTail > 1 ||
1460 FracClusterSize1 > 1 || FracClusterSize2 > 1) {
1461 if (stationName >= 2) {
1462 index += m_FracClusterSize1_A.size() / 2 * measuresPhi;
1463 if (index >= m_FracClusterSize1_A.size() ||
1464 index >= m_FracClusterSize2_A.size() ||
1465 index >= m_FracClusterSizeTail_A.size() ||
1466 index >= m_MeanClusterSizeTail_A.size()) {
1467 ATH_MSG_ERROR("Index out of array in determineClusterSize SideA " << index << " statName " << stationName);
1468 return 1;
1469 }
1470 FracClusterSize1 = m_FracClusterSize1_A[index];
1471 FracClusterSize2 = m_FracClusterSize2_A[index];
1472 FracClusterSizeTail = m_FracClusterSizeTail_A[index];
1473 MeanClusterSizeTail = m_MeanClusterSizeTail_A[index];
1474
1475 if (stationEta < 0) {
1476 index += m_FracClusterSize1_C.size() / 2 * measuresPhi - m_FracClusterSize1_A.size() / 2 * measuresPhi;
1477 if (index > m_FracClusterSize1_C.size() || index > m_FracClusterSize2_C.size() ||
1479 ATH_MSG_ERROR("Index out of array in determineClusterSize SideC " << index << " statName " << stationName);
1480 return 1;
1481 }
1482
1483 FracClusterSize1 = m_FracClusterSize1_C[index];
1484 FracClusterSize2 = m_FracClusterSize2_C[index];
1485 FracClusterSizeTail = m_FracClusterSizeTail_C[index];
1486 MeanClusterSizeTail = m_MeanClusterSizeTail_C[index];
1487 }
1488 } else {
1489 FracClusterSize1 = m_FracClusterSize1_BIS78;
1490 FracClusterSize2 = m_FracClusterSize2_BIS78;
1491 FracClusterSizeTail = m_FracClusterSizeTail_BIS78;
1492 MeanClusterSizeTail = m_MeanClusterSizeTail_BIS78;
1493 }
1494 }
1495 }
1496 FracClusterSize1 = std::min(FracClusterSize1, 1.);
1497 FracClusterSize2 = std::min(FracClusterSize2, 1.);
1498 FracClusterSizeTail = std::min(FracClusterSizeTail, 1.);
1499 float FracTot = FracClusterSize1 + FracClusterSize2 + FracClusterSizeTail;
1500 if (FracTot != 1. && FracTot > 0) {
1501 FracClusterSize1 = FracClusterSize1 / FracTot;
1502 FracClusterSize2 = FracClusterSize2 / FracTot;
1503 FracClusterSizeTail = FracClusterSizeTail / FracTot;
1504 }
1505 if (MeanClusterSizeTail < 0 || MeanClusterSizeTail > 10) MeanClusterSizeTail = 1;
1506
1507 ATH_MSG_VERBOSE("ClusterSize Final " << FracClusterSize1 << " FracClusterSize1 " << FracClusterSize2 << " FracClusterSize2 "
1508 << FracClusterSizeTail << " " << FracClusterSizeTail << " MeanClusterSizeTail "
1509 << MeanClusterSizeTail);
1510
1511 float FracClusterSize1plus2 = FracClusterSize1 + FracClusterSize2;
1512 float ITot = FracClusterSize1 + FracClusterSize2 + FracClusterSizeTail;
1513
1514 if (FracClusterSize1plus2 != 0) {
1515 // FracClusterSize1norm = FracClusterSize1 / FracClusterSize1plus2 ; // not used
1516 FracClusterSize2norm = FracClusterSize2 / FracClusterSize1plus2;
1517 }
1518
1519 float rndmCS = CLHEP::RandFlat::shoot(rndmEngine, ITot);
1520
1521 if (stationName >= 2) { // Legacy RPCs
1522 // Expanded CS2 of 1.3 to match average CS1 and CS2 (to be investigate)
1523 if (rndmCS < FracClusterSize1plus2) {
1524 // deterministic assignment of CS 1 or 2
1525 if (xstripnorm <= FracClusterSize2norm / 2. * 1.3) {
1526 ClusterSize = -2;
1527 } else if ((1.0 - FracClusterSize2norm / 2. * 1.3) <= xstripnorm) {
1528 ClusterSize = 2;
1529 } else {
1530 ClusterSize = 1;
1531 }
1533 float rndmCS1_2 = CLHEP::RandFlat::shoot(rndmEngine, 1);
1534 ClusterSize = 1 + (rndmCS1_2 < FracClusterSize2norm);
1535 }
1536
1537 } else if ((FracClusterSize1plus2 <= rndmCS) && (rndmCS <= ITot)) {
1538 ClusterSize = m_FirstClusterSizeInTail;
1539 ClusterSize += int(CLHEP::RandExponential::shoot(rndmEngine, MeanClusterSizeTail));
1540 float rndmLR = CLHEP::RandFlat::shoot(rndmEngine, 1.0);
1541 if (rndmLR > 0.5) ClusterSize = -ClusterSize;
1542 } else {
1543 ClusterSize = 1;
1544 }
1545
1546 } else { // NRPCs
1547 if (rndmCS < FracClusterSize1) {
1548 ClusterSize = 1;
1549 } else if (rndmCS < FracClusterSize1 + FracClusterSize2) {
1550 ClusterSize = 2;
1551 } else {
1552 ClusterSize = int(CLHEP::RandExponential::shoot(rndmEngine, MeanClusterSizeTail));
1553 }
1554 ClusterSize = std::max(ClusterSize, 1);
1555 if (ClusterSize > 1) {
1556 float rndmLR = CLHEP::RandFlat::shoot(rndmEngine, 1.0);
1557 if (rndmLR > 0.5) ClusterSize = -ClusterSize;
1558 }
1559 }
1560
1561 // negative CS correspond to left asymmetric cluster with respect to nstrip
1562 return ClusterSize;
1563}
1565 double qcharge = 1.;
1566 const int particlePdgId = genParticle->pdg_id();
1567 // charge calculation
1568 qcharge = (static_cast<double>((std::abs(particlePdgId) / 1000) % 100)) / (static_cast<double>((std::abs(particlePdgId) / 10) % 100));
1569 qcharge = ((static_cast<double>((static_cast<int>(qcharge * 100))))) / 100;
1570 if (particlePdgId < 0.0) qcharge = -qcharge;
1571 // BetaGamma calculation
1572 const double QPx = genParticle->momentum().px();
1573 const double QPy = genParticle->momentum().py();
1574 const double QPz = genParticle->momentum().pz();
1575 const double QE = genParticle->momentum().e();
1576 const double QM2 = std::pow(QE, 2) - std::pow(QPx, 2) - std::pow(QPy, 2) - std::pow(QPz, 2);
1577 const double QP = std::hypot(QPx, QPy, QPz);
1578 const double QM = QM2 >=0 ? std::sqrt(QM2) : -1.;
1579
1580 const double qbetagamma = QM > 0. ? QP / QM : -1.;
1581
1582 // find the i in the array
1583 int i_e = -1;
1584 for (int i = 0; i < 12; i++) {
1585 if (Charge[i] == std::abs(qcharge)) {
1586 i_e = i;
1587 break;
1588 }
1589 }
1590 int i_v = -99, j_v = 99;
1591 if (qbetagamma != -1) {
1592 for (int i = 0; i < 15; i++) {
1593 if (Velocity[i] <= qbetagamma) { i_v = i; }
1594 }
1595 for (int i = 14; i >= 0; i--) {
1596 if (Velocity[i] >= qbetagamma) { j_v = i; }
1597 }
1598 }
1599 // calculate the efficiency according to charge and velocity. Using linear function to calculate efficiency of a specific velocity
1600 // between velocity1 and velocity2
1601 double eff_fcp = 1.0, eff_muon = 1.0;
1602 if (i_e >= 0 && i_e <= 11) {
1603 if (validIndex(j_v, N_Velocity) && validIndex(i_v, N_Velocity) && (j_v - i_v) == 1) {
1604 const double delta_v = Velocity[i_v] - Velocity[j_v];
1605 eff_fcp = (Eff_garfield[i_e][i_v] - Eff_garfield[i_e][j_v]) / delta_v * qbetagamma +
1606 (Eff_garfield[i_e][j_v] * Velocity[i_v] - Eff_garfield[i_e][i_v] * Velocity[j_v]) / delta_v;
1607 eff_muon = (Eff_garfield[11][i_v] - Eff_garfield[11][j_v]) / delta_v * qbetagamma +
1608 (Eff_garfield[11][j_v] * Velocity[i_v] - Eff_garfield[11][i_v] * Velocity[j_v]) / delta_v;
1609 } else if (i_v == 14 && j_v == 99) {
1610 eff_fcp = Eff_garfield[i_e][14];
1611 eff_muon = Eff_garfield[11][14];
1612 } else if (i_v == -99 && j_v == 0) {
1613 eff_fcp = Eff_garfield[i_e][0];
1614 eff_muon = Eff_garfield[11][0];
1615 } else {
1616 ATH_MSG_WARNING("Wrong particle with unknown velocity! Scale factor is set to be 1.");
1617 }
1618 } else {
1619 ATH_MSG_WARNING("Wrong particle with unknown charge! Scale factor is set to be 1.");
1620 }
1621 // A scale factor is calculated by efficiency of fcp / efficiency of muon(charge==1.0
1622 const double eff_SF = eff_fcp / eff_muon;
1623 return eff_SF;
1624}
1625
1626double RpcDigitizationTool::timeOverThreshold(CLHEP::HepRandomEngine* rndmEngine) {
1627 //mn Time-over-threshold modeled as a narrow and a wide gaussian
1628 //mn based on the fit documented in https://its.cern.ch/jira/browse/ATLASRECTS-7820
1629 constexpr double tot_mean_narrow = 16.;
1630 constexpr double tot_sigma_narrow = 2.;
1631 constexpr double tot_mean_wide = 15.;
1632 constexpr double tot_sigma_wide = 4.5;
1633
1634 double thetot = 0.;
1635
1636 if (CLHEP::RandFlat::shoot(rndmEngine)<0.75) {
1637 thetot = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot_mean_narrow, tot_sigma_narrow);
1638 } else {
1639 thetot = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot_mean_wide, tot_sigma_wide);
1640 }
1641
1642 return (thetot > 0.) ? thetot : 0.;
1643}
float hitTime(const AFP_SIDSimHit &hit)
constexpr std::array< T, N > make_array(const T &def_val)
Helper function to initialize in-place arrays with non-zero values.
Definition ArrayHelper.h:10
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#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)
ATLAS-specific HepMC functions.
std::vector< xAOD::EventInfo::SubEvent >::const_iterator SubEventIterator
Definition IPileUpTool.h:22
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
bool hit(const Container &ids, int pdgId)
static Double_t sc
AtlasHitsVector< RPCSimHit > RPCSimHitCollection
struct TBPatternUnitContext Unknown
#define x
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:154
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:108
size_type size() const
const T * get(size_type n) const
Access an element, as an rvalue.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
virtual unsigned int size() const =0
This class saves the "context" of an expanded identifier (ExpandedIdentifier) for compact or hash ver...
Definition IdContext.h:26
size_type begin_index() const
Definition IdContext.h:45
size_type end_index() const
Definition IdContext.h:46
value_type get_compact() const
Get the compact id.
This is a "hash" representation of an Identifier.
Identifier32 get_identifier32() const
Get the 32-bit version Identifier, will be invalid if >32 bits needed.
virtual const Amg::Transform3D & transform() const override
Return local to global transform.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const RpcReadoutElement * getRpcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
An RpcReadoutElement corresponds to a single RPC module; therefore typicaly a barrel muon station con...
int nGasGapPerLay() const
returns the number of gasgaps
int NphiStripPanels() const
returns the number of phi strip panels (1 or 2)
virtual int stripNumber(const Amg::Vector2D &pos, const Identifier &id) const override final
strip number corresponding to local position.
Amg::Vector3D localGasGapPos(const Identifier &id) const
Returns the position of the gasGap w.r.t. rest frame of the chamber.
Amg::Transform3D localToGlobalTransf(const Identifier &id) const
int Nstrips(bool measphi) const
returns the number of strips for the phi or eta plane
virtual int numberOfLayers(bool measphi=true) const override final
number of layers in phi/eta projection, same for eta/phi planes
double StripPitch(bool measphi) const
returns the strip pitch for the phi or eta plane
std::pair< HepMcParticleLink, MuonMCData > Deposit
Definition MuonSimData.h:66
Gaudi::Property< int > m_vetoPileUpTruthLinks
PileUpToolBase(const std::string &type, const std::string &name, const IInterface *parent)
std::optional< double > getFracClusterSize2(const Identifier &) const
std::optional< int > getProjectedTrack(const Identifier &) const
std::optional< double > getFracDeadStrip(const Identifier &) const
std::optional< double > getFracClusterSize1(const Identifier &) const
std::optional< double > getGapEfficiency(const Identifier &) const
std::optional< double > getEfficiency(const Identifier &) const
std::optional< double > getMeanClusterSize(const Identifier &) const
std::pair< bool, bool > detectionEfficiency(const EventContext &ctx, const Identifier &ideta, const Identifier &idphi, CLHEP::HepRandomEngine *rndmEngine, const HepMcParticleLink &trkParticle) const
Evaluate detection efficiency.
Gaudi::Property< float > m_MeanClusterSizeTail_BIS78
Gaudi::Property< double > m_CorrJitter_BIS78
std::vector< std::unique_ptr< RpcDigitCollection > > Collections_t
bool outsideWindow(double time) const
const RpcHitIdHelper * m_muonHelper
int determineClusterSize(const EventContext &ctx, const Identifier &id, double xstripnorm, CLHEP::HepRandomEngine *rndmEngine) const
virtual StatusCode mergeEvent(const EventContext &ctx) override final
When being run from PileUpToolsAlgs, this method is called at the end of the subevts loop.
virtual StatusCode initialize() override final
Initialize.
long long int PackMCTruth(float proptime, float tof, float posx, float posz) const
Gaudi::Property< bool > m_turnON_efficiency
double FCPEfficiency(const HepMC::ConstGenParticlePtr &genParticle) const
Gaudi::Property< bool > m_EfficiencyPatchForBMShighEta
Gaudi::Property< bool > m_patch_for_rpc_time
std::array< int, 3 > physicalClusterSize(const EventContext &ctx, const MuonGM::RpcReadoutElement *reEle, const Identifier &id, const Amg::Vector3D &posAtCentre, CLHEP::HepRandomEngine *rndmEngine) const
Cluster simulation: first step.
RpcDigitizationTool(const std::string &type, const std::string &name, const IInterface *pIID)
Gaudi::Property< int > m_FirstClusterSizeInTail
Gaudi::Property< std::vector< double > > m_FracClusterSize2_A
ServiceHandle< IAthRNGSvc > m_rndmSvc
Gaudi::Property< double > m_timeWindowLowerOffset
Gaudi::Property< float > m_FracClusterSize2_BIS78
Amg::Transform3D fromSimHitToLayer(const MuonGM::RpcReadoutElement *readOutEle, const Identifier &layerId) const
Returns the position of the hit expressed in the gasGap coordinate system.
Gaudi::Property< int > m_CutProjectedTracks
Gaudi::Property< double > m_timeWindowUpperOffset
Gaudi::Property< std::vector< double > > m_FracClusterSize1_A
Gaudi::Property< int > m_deadTime
Gaudi::Property< bool > m_kill_deadstrips
Gaudi::Property< bool > m_ClusterSize_fromCOOL
std::array< int, 3 > TurnOnStrips(const MuonGM::RpcReadoutElement *reEle, std::array< int, 3 > &&pcs, const Identifier &id) const
Cluster simulation: second step.
Gaudi::Property< bool > m_includePileUpTruth
SG::WriteHandleKey< RPCSimHitCollection > m_simHitValidKey
SG::WriteHandleKey< RpcDigitContainer > m_outputDigitCollectionKey
StatusCode initializeRunDependentParameters()
Gaudi::Property< bool > m_ClusterSize_BIS78_fromCOOL
Gaudi::Property< bool > m_ClusterSize1_2uncorr
Gaudi::Property< bool > m_ignoreRunDepConfig
ServiceHandle< PileUpMergeSvc > m_mergeSvc
Gaudi::Property< std::vector< double > > m_MeanClusterSizeTail_A
std::vector< std::unique_ptr< RPCSimHitCollection > > m_RPCHitCollList
SG::WriteHandleKey< MuonSimDataCollection > m_outputSDO_CollectionKey
SG::ReadCondHandleKey< RpcCondDbData > m_readKey
Gaudi::Property< std::vector< double > > m_MeanClusterSizeTail_C
std::map< Identifier, std::vector< MuonSimData::Deposit > > m_sdo_tmp_map
Gaudi::Property< std::vector< float > > m_OnlyPhiEff_C
Gaudi::Property< bool > m_validationSetup
Gaudi::Property< std::vector< double > > m_FracClusterSize1_C
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_detMgrKey
virtual StatusCode prepareEvent(const EventContext &ctx, const unsigned int) override final
When being run from PileUpToolsAlgs, this method is called at the start of the subevts loop.
Gaudi::Property< double > m_UncorrJitter_BIS78
virtual StatusCode processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) override final
When being run from PileUpToolsAlgs, this method is called for each active bunch-crossing to process ...
double PropagationTime(const MuonGM::RpcReadoutElement *reEle, const Identifier &id, const Amg::Vector3D &globPos) const
Calculates the propagation time along the strip.
Gaudi::Property< std::vector< float > > m_OnlyPhiEff_A
Gaudi::Property< float > m_FracClusterSizeTail_BIS78
Gaudi::Property< std::vector< double > > m_FracClusterSizeTail_A
Gaudi::Property< float > m_OnlyEtaEff_BIS78
Gaudi::Property< std::vector< double > > m_FracClusterSize2_C
std::unique_ptr< TimedHitCollection< RPCSimHit > > m_thpcRPC
StatusCode getNextEvent(const EventContext &ctx)
Get next event and extract collection of hit collections:
Gaudi::Property< std::vector< float > > m_OnlyEtaEff_C
Gaudi::Property< std::string > m_RPC_TimeSchema
const RpcIdHelper * m_idHelper
static void UnPackMCTruth(double theWord, float &proptime, float &tof, float &posy, float &posz)
static double timeOverThreshold(CLHEP::HepRandomEngine *rndmEngine)
Gaudi::Property< float > m_CutMaxClusterSize
SG::ReadHandleKey< RPCSimHitCollection > m_hitsContainerKey
Gaudi::Property< float > m_OnlyPhiEff_BIS78
Gaudi::Property< bool > m_turnON_clustersize
Gaudi::Property< std::vector< float > > m_PhiAndEtaEff_A
Gaudi::Property< bool > m_RPCInfoFromDb
Gaudi::Property< double > m_rpc_time_shift
Gaudi::Property< float > m_FracClusterSize1_BIS78
Gaudi::Property< double > m_CorrJitter
Gaudi::Property< std::vector< float > > m_OnlyEtaEff_A
Gaudi::Property< bool > m_Efficiency_fromCOOL
Gaudi::Property< double > m_UncorrJitter
Calculates the position of the hit wrt to the strip panel this transformation is needed since the imp...
std::string m_inputHitCollectionName
StatusCode doDigitization(const EventContext &ctx, Collections_t &collections, MuonSimDataCollection *sdoContainer)
Digitization functionality shared with RPC_PileUpTool.
virtual StatusCode processAllSubEvents(const EventContext &ctx) override final
alternative interface which uses the PileUpMergeSvc to obtain all the required SubEvents.
StatusCode retrieveCondData(const EventContext &ctx, const SG::ReadCondHandleKey< CondType > &key, const CondType *&condPtr) const
Gaudi::Property< bool > m_onlyUseContainerName
Gaudi::Property< std::vector< float > > m_PhiAndEtaEff_C
Gaudi::Property< bool > m_Efficiency_BIS78_fromCOOL
Gaudi::Property< std::vector< double > > m_FracClusterSizeTail_C
Gaudi::Property< bool > m_BOG_BOF_DoubletR2_OFF
Gaudi::Property< bool > m_muonOnlySDOs
Gaudi::Property< bool > m_sdoAreOnlyDigits
Gaudi::Property< float > m_PhiAndEtaEff_BIS78
static const RpcHitIdHelper * GetHelper(unsigned int nGasGaps=2)
const_pointer_type cptr()
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
std::string store() const
Return the name of the store holding the object we are proxying.
const std::string & name() const
Return the StoreGate ID for the referenced object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
TimedVector::const_iterator const_iterator
a smart pointer to a hit that also provides access to the extended timing info of the host event.
Definition TimedHitPtr.h:18
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
Definition TimedHitPtr.h:47
constexpr bool simData
Definition constants.h:36
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Transform3D getRotateY3D(double angle)
Rotate the coordinate system by an angle around the z-axis.
HepMC3::ConstGenParticlePtr ConstGenParticlePtr
Definition GenParticle.h:20
bool ignoreTruthLink(const T &p, bool vetoPileUp)
Helper function for SDO creation in PileUpTools.
bool isGenericMultichargedParticle(const T &p)
In addition, there is a need to identify ”Q-ball” and similar very exotic (multi-charged) particles w...
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
USAGE: openCoraCool.exe "COOLONL_SCT/COMP200".
Definition index.py:1
std::list< value_t > type
type of the collection of timed data object
a struct encapsulating the identifier of a pile-up event
index_type index() const
the index of the component event in PileUpEventInfo
PileUpType type() const
the pileup type - minbias, cavern, beam halo, signal?
time_type time() const
bunch xing time in ns
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP
Definition trapping_fp.h:24
int run(int argc, char *argv[])