ATLAS Offline Software
Loading...
Searching...
No Matches
MuonDigitization/MDT_Digitization/src/MdtDigitizationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6//
7// MdtDigitizationTool:
8// Athena algorithm which produces MDTDigits out of MHits.
9// ------------
10// Authors:
11// Daniela Rebuzzi (daniela.rebuzzi@pv.infn.it)
12// Ketevi A. Assamagan (ketevi@lbn.gov)
13// Modified by:
14// 2004-03-02 Niels Van Eldik (nveldik@nikhef.nl)
15// Modified by:
16// 2004-04-05 Daniel Levin (dslevin@umich.edu)
17// generate drift time deltas based on wire sag.
18// first pass: assume wires are geomtrically centered-
19// but have top/bottom RT functions that would obtain
20// if the wire was off axis by an amount determined
21// by the tube length, orientation, hit location and track angle
22// Modified by:
23// 2004-02-08 Daniel Levin (dslevin@umich.edu)
24// generate new impact parameters based on physical wire sag.
25// 2012-7-5 Shannon Walch (srwalch@umich.edu)
26// implement bug fixes in RT wiresag calculations
27// Modified by:
28// Dinos Bachas (konstantinos.bachas@cern.ch)
29//
31
32// MDT digitization includes
33#include "MdtDigitizationTool.h"
34
36
37// Gaudi - Core
39
40// Geometry
47// Pile-up
48
49// Truth
53
54// Random Numbers
56
57// Calibration Service
60namespace {
61 // what about this? does this also need to be 1/m_signalSpeed ?
62 constexpr double s_inv_c_light(1. / Gaudi::Units::c_light);
63} // namespace
64MdtDigitizationTool::MdtDigitizationTool(const std::string& type, const std::string& name, const IInterface* pIID) :
65 PileUpToolBase(type, name, pIID) {}
66
68 ATH_MSG_INFO("Configuration MdtDigitizationTool");
69 ATH_MSG_INFO("RndmSvc " << m_rndmSvc);
70 ATH_MSG_INFO("DigitizationTool " << m_digiTool);
71 ATH_MSG_INFO("OffsetTDC " << m_offsetTDC);
72 ATH_MSG_INFO("ns2TDCAMT " << m_ns2TDCAMT);
73 ATH_MSG_INFO("ns2TDCHPTDC " << m_ns2TDCHPTDC);
74 ATH_MSG_INFO("ResolutionTDC " << m_resTDC);
75 ATH_MSG_INFO("SignalSpeed " << m_signalSpeed);
76 ATH_MSG_INFO("InputObjectName " << m_inputObjectName);
77 ATH_MSG_INFO("OutputObjectName " << m_outputObjectKey.key());
78 ATH_MSG_INFO("OutputSDOName " << m_outputSDOKey.key());
79 ATH_MSG_INFO("UseAttenuation " << m_useAttenuation);
80 ATH_MSG_INFO("UseTof " << m_useTof);
81 ATH_MSG_INFO("UseProp " << m_useProp);
82 ATH_MSG_INFO("UseDeformations " << m_useDeformations);
83 ATH_MSG_INFO("UseTimeWindow " << m_useTimeWindow);
84 ATH_MSG_INFO("BunchCountOffset " << m_bunchCountOffset);
85 ATH_MSG_INFO("MatchingWindow " << m_matchingWindow);
86 ATH_MSG_INFO("MaskWindow " << m_maskWindow);
87 ATH_MSG_INFO("DeadTime " << m_deadTime);
88 ATH_MSG_INFO("DiscardEarlyHits " << m_DiscardEarlyHits);
89 ATH_MSG_INFO("CheckSimHits " << m_checkMDTSimHits);
90 ATH_MSG_INFO("UseTwin " << m_useTwin);
91 ATH_MSG_INFO("UseAllBOLTwin " << m_useAllBOLTwin);
92 ATH_MSG_INFO("ResolutionTwinTube " << m_resTwin);
93 ATH_MSG_INFO("DoQballCharge " << m_DoQballCharge);
94 if (!m_useTof) {
95 ATH_MSG_INFO("UseCosmicsOffSet1 " << m_useOffSet1);
96 ATH_MSG_INFO("UseCosmicsOffSet2 " << m_useOffSet2);
97 }
98 ATH_MSG_INFO("IncludePileUpTruth " << m_includePileUpTruth);
99 ATH_MSG_INFO("VetoPileUpTruthLinks " << m_vetoPileUpTruthLinks);
100
101 // initialize transient detector store and MuonGeoModel OR MuonDetDescrManager
102 if (detStore()->contains<MuonGM::MuonDetectorManager>("Muon")) {
103 ATH_CHECK(detStore()->retrieve(m_MuonGeoMgr));
104 ATH_MSG_DEBUG("Retrieved MuonGeoModelDetectorManager from StoreGate");
105 }
106
107 // initialize MuonIdHelperSvc
108 ATH_CHECK(m_idHelperSvc.retrieve());
109
110 if (m_onlyUseContainerName) { ATH_CHECK(m_mergeSvc.retrieve()); }
111
112 // check the input object name
113 if (m_hitsContainerKey.key().empty()) {
114 ATH_MSG_FATAL("Property InputObjectName not set !");
115 return StatusCode::FAILURE;
116 }
118 ATH_MSG_DEBUG("Input objects in container : '" << m_inputObjectName << "'");
119
120 // Initialize ReadHandleKey
121 ATH_CHECK(m_hitsContainerKey.initialize());
122 ATH_CHECK(m_calibDbKey.initialize());
123
124 // initialize the output WriteHandleKeys
125 ATH_CHECK(m_outputObjectKey.initialize());
126 ATH_MSG_VERBOSE("Initialized WriteHandleKey: " << m_outputObjectKey);
127 ATH_CHECK(m_outputSDOKey.initialize());
128 ATH_MSG_VERBOSE("Initialized WriteHandleKey: " << m_outputSDOKey);
129 ATH_MSG_DEBUG("Output Digits: '" << m_outputObjectKey.key() << "'");
130
131 // simulation identifier helper
132 m_muonHelper = MdtHitIdHelper::GetHelper(m_idHelperSvc->mdtIdHelper().tubeMax());
133
134 // get the r->t conversion tool
135 ATH_CHECK(m_digiTool.retrieve());
136 ATH_MSG_DEBUG("Retrieved digitization tool!" << m_digiTool);
137
138 ATH_CHECK(m_rndmSvc.retrieve());
139 ATH_CHECK(m_readKey.initialize(!m_readKey.empty()));
140 return StatusCode::SUCCESS;
141}
142
143StatusCode MdtDigitizationTool::prepareEvent(const EventContext& /*ctx*/, unsigned int nInputEvents) {
144 ATH_MSG_DEBUG("MdtDigitizationTool::prepareEvent() called for " << nInputEvents << " input events");
145
146 m_MDTHitCollList.clear();
147 m_thpcMDT = std::make_unique<TimedHitCollection<MDTSimHit>>();
148
149 return StatusCode::SUCCESS;
150}
151
152StatusCode MdtDigitizationTool::processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) {
153 ATH_MSG_DEBUG("MdtDigitizationTool::processBunchXing() " << bunchXing);
154
156 TimedHitCollList hitCollList;
157
158 if (!(m_mergeSvc->retrieveSubSetEvtData(m_inputObjectName, hitCollList, bunchXing, bSubEvents, eSubEvents).isSuccess()) &&
159 hitCollList.empty()) {
160 ATH_MSG_ERROR("Could not fill TimedHitCollList");
161 return StatusCode::FAILURE;
162 } else {
163 ATH_MSG_VERBOSE(hitCollList.size() << " MDTSimHitCollection with key " << m_inputObjectName << " found");
164 }
165
166 TimedHitCollList::iterator iColl(hitCollList.begin());
167 TimedHitCollList::iterator endColl(hitCollList.end());
168
169 // Iterating over the list of collections
170 for (; iColl != endColl; ++iColl) {
171 MDTSimHitCollection* hitCollPtr = new MDTSimHitCollection(*iColl->second);
172 PileUpTimeEventIndex timeIndex(iColl->first);
173
174 ATH_MSG_DEBUG("MDTSimHitCollection found with " << hitCollPtr->size() << " hits");
175 ATH_MSG_VERBOSE("time index info. time: " << timeIndex.time() << " index: " << timeIndex.index() << " type: " << timeIndex.type());
176
177 m_thpcMDT->insert(timeIndex, hitCollPtr);
178 m_MDTHitCollList.push_back(hitCollPtr);
179 }
180
181 return StatusCode::SUCCESS;
182}
183
184StatusCode MdtDigitizationTool::getNextEvent(const EventContext& ctx) {
185 ATH_MSG_DEBUG("MdtDigitizationTool::getNextEvent()");
186
187 // get the container(s)
189
190 // In case of single hits container just load the collection using read handles
193 if (!hitCollection.isValid()) {
194 ATH_MSG_ERROR("Could not get MDTSimHitCollection container " << hitCollection.name() << " from store "
195 << hitCollection.store());
196 return StatusCode::FAILURE;
197 }
198
199 // create a new hits collection
200 m_thpcMDT = std::make_unique<TimedHitCollection<MDTSimHit>>(1);
201 m_thpcMDT->insert(0, hitCollection.cptr());
202 ATH_MSG_DEBUG("MDTSimHitCollection found with " << hitCollection->size() << " hits");
203
204 return StatusCode::SUCCESS;
205 }
206
207 // this is a list<info<time_t, DataLink<MDTSimHitCollection> > >
208 TimedHitCollList hitCollList;
209
210 if (!(m_mergeSvc->retrieveSubEvtsData(m_inputObjectName, hitCollList).isSuccess())) {
211 ATH_MSG_ERROR("Could not fill TimedHitCollList");
212 return StatusCode::FAILURE;
213 }
214 if (hitCollList.empty()) {
215 ATH_MSG_ERROR("TimedHitCollList has size 0");
216 return StatusCode::FAILURE;
217 } else {
218 ATH_MSG_DEBUG(hitCollList.size() << " MDTSimHitCollections with key " << m_inputObjectName << " found");
219 }
220
221 // create a new hits collection
222 m_thpcMDT = std::make_unique<TimedHitCollection<MDTSimHit>>();
223
224 // now merge all collections into one
225 TimedHitCollList::iterator iColl(hitCollList.begin());
226 TimedHitCollList::iterator endColl(hitCollList.end());
227 while (iColl != endColl) {
228 const MDTSimHitCollection* p_collection(iColl->second);
229 m_thpcMDT->insert(iColl->first, p_collection);
230 ATH_MSG_DEBUG("MDTSimHitCollection found with " << p_collection->size() << " hits");
231 ++iColl;
232 }
233 return StatusCode::SUCCESS;
234}
235
236CLHEP::HepRandomEngine* MdtDigitizationTool::getRandomEngine(const std::string& streamName, const EventContext& ctx) const {
237 ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this, streamName);
238 std::string rngName = name() + streamName;
239 rngWrapper->setSeed(rngName, ctx);
240 return rngWrapper->getEngine(ctx);
241}
242
243StatusCode MdtDigitizationTool::mergeEvent(const EventContext& ctx) {
244 ATH_MSG_DEBUG("MdtDigitizationTool::in mergeEvent()");
245
246 // create and record the Digit container in StoreGate
248 ATH_CHECK(digitContainer.record(std::make_unique<MdtDigitContainer>(m_idHelperSvc->mdtIdHelper().module_hash_max())));
249 ATH_MSG_DEBUG("Recorded MdtDigitContainer called " << digitContainer.name() << " in store " << digitContainer.store());
250
251 // create and record the SDO container in StoreGate
253 ATH_CHECK(sdoContainer.record(std::make_unique<MuonSimDataCollection>()));
254 ATH_MSG_DEBUG("Recorded MuonSimDataCollection called " << sdoContainer.name() << " in store " << sdoContainer.store());
255
256 Collections_t collections;
257 StatusCode status = doDigitization(ctx, collections, sdoContainer.ptr());
258 if (status.isFailure()) { ATH_MSG_ERROR("doDigitization Failed"); }
259
260 for (size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
261 if (collections[coll_hash]) {
262 ATH_CHECK( digitContainer->addCollection (collections[coll_hash].release(), coll_hash) );
263 }
264 }
265
266 // Clean-up
267 std::vector<MDTSimHitCollection*>::iterator MDTHitColl = m_MDTHitCollList.begin();
268 std::vector<MDTSimHitCollection*>::iterator MDTHitCollEnd = m_MDTHitCollList.end();
269 while (MDTHitColl != MDTHitCollEnd) {
270 delete (*MDTHitColl);
271 ++MDTHitColl;
272 }
273 m_MDTHitCollList.clear();
274
275 return status;
276}
277
278StatusCode MdtDigitizationTool::processAllSubEvents(const EventContext& ctx) {
279 ATH_MSG_DEBUG("MdtDigitizationTool::processAllSubEvents()");
280
281 // create and record the Digit container in StoreGate
283 ATH_CHECK(digitContainer.record(std::make_unique<MdtDigitContainer>(m_idHelperSvc->mdtIdHelper().module_hash_max())));
284 ATH_MSG_DEBUG("Recorded MdtDigitContainer called " << digitContainer.name() << " in store " << digitContainer.store());
285
286 // create and record the SDO container in StoreGate
288 ATH_CHECK(sdoContainer.record(std::make_unique<MuonSimDataCollection>()));
289 ATH_MSG_DEBUG("Recorded MuonSimDataCollection called " << sdoContainer.name() << " in store " << sdoContainer.store());
290
291 StatusCode status = StatusCode::SUCCESS;
292 if (!m_thpcMDT) {
293 status = getNextEvent(ctx);
294 if (StatusCode::FAILURE == status) {
295 ATH_MSG_INFO("There are no MDT hits in this event");
296 return status;
297 }
298 }
299
300 Collections_t collections;
301 ATH_CHECK(doDigitization(ctx, collections, sdoContainer.ptr()));
302
303 for (size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
304 if (collections[coll_hash]) {
305 ATH_CHECK( digitContainer->addCollection (collections[coll_hash].release(), coll_hash) );
306 }
307 }
308
309 return status;
310}
311
312StatusCode MdtDigitizationTool::doDigitization(const EventContext& ctx, Collections_t& collections,
313 MuonSimDataCollection* sdoContainer) {
314 // Set the RNGs to use for this event.
315 CLHEP::HepRandomEngine* rndmEngine = getRandomEngine("", ctx);
316 CLHEP::HepRandomEngine* twinRndmEngine = getRandomEngine("Twin", ctx);
317 CLHEP::HepRandomEngine* toolRndmEngine = getRandomEngine(m_digiTool->name(), ctx);
318
319 // get the iterator infos for this DetEl
320 // iterate over hits and fill id-keyed drift time map
322
323 // Perform null check on m_thpcMDT
324 if (!m_thpcMDT) {
325 ATH_MSG_ERROR("m_thpcMDT is null");
326 return StatusCode::FAILURE;
327 }
328
329 while (m_thpcMDT->nextDetectorElement(i, e)) {
330 // Loop over the hits:
331 while (i != e) {
332 handleMDTSimHit(ctx, *i, twinRndmEngine, toolRndmEngine);
333 ++i;
334 }
335 }
336
337 // loop over drift time map entries, convert to tdc value and construct/store the digit
338 createDigits(ctx, collections, sdoContainer, rndmEngine);
339
340 // reset hits
341 m_hits.clear();
342
343 // reset the pointer if it is not null
344 m_thpcMDT.reset();
345
346 return StatusCode::SUCCESS;
347}
348
349bool MdtDigitizationTool::handleMDTSimHit(const EventContext& ctx,
350 const TimedHitPtr<MDTSimHit>& phit, CLHEP::HepRandomEngine* twinRndmEngine,
351 CLHEP::HepRandomEngine* toolRndmEngine) {
352 const MDTSimHit& hit(*phit);
353 MDTSimHit newSimhit(*phit); // hit can be modified later
354
355 double globalHitTime(hitTime(phit));
356
357 // Important checks for hits (global time, position along tube, masked chambers etc..) DO NOT SET THIS CHECK TO FALSE IF YOU DON'T KNOW
358 // WHAT YOU'RE DOING !
359 if (m_checkMDTSimHits && !checkMDTSimHit(ctx, hit)) return false;
360
361 const int id = hit.MDTid();
362 double driftRadius = hit.driftRadius();
363 ATH_MSG_DEBUG("Hit bunch time " << globalHitTime - hit.globalTime() << " tot " << globalHitTime << " tof " << hit.globalTime()
364 << " driftRadius " << driftRadius);
365
366 std::string stationName = m_muonHelper->GetStationName(id);
367 int stationEta = m_muonHelper->GetZSector(id);
368 int stationPhi = m_muonHelper->GetPhiSector(id);
369 int multilayer = m_muonHelper->GetMultiLayer(id);
370 int layer = m_muonHelper->GetLayer(id);
371 int tube = m_muonHelper->GetTube(id);
372
373 // construct Atlas identifier from components
374 Identifier DigitId = m_idHelperSvc->mdtIdHelper().channelID(stationName, stationEta, stationPhi, multilayer, layer, tube);
375
376 // get distance to readout
377 double distRO(0.);
378
379 // find the detector element associated to the hit
380 const MuonGM::MdtReadoutElement* element = m_MuonGeoMgr->getMdtReadoutElement(DigitId);
381
382 if (!element) {
383 ATH_MSG_ERROR("MuonGeoManager does not return valid element for given id!");
384 return false;
385 } else {
386 distRO = element->tubeFrame_localROPos(DigitId).z();
387 }
388
389 if (m_useDeformations) {
390 newSimhit = applyDeformations(hit, element, DigitId);
391 driftRadius = newSimhit.driftRadius();
392 }
393
394 // store local hit position + sign
395 GeoCorOut result = correctGeometricalWireSag(hit, DigitId, element);
396 if (m_useDeformations) { result = correctGeometricalWireSag(newSimhit, DigitId, element); }
397
398 // correctly set sign of drift radius
399 driftRadius *= result.trackingSign;
400
401 //+Implementation for RT_Relation_DB_Tool
402
403 // total from the hit to the tube endplug
404 double distanceToRO = 0.;
405 if (distRO < 0. && hit.localPosition().z() > 0.) {
406 distanceToRO = -distRO + hit.localPosition().z();
407 }
408 else {
409 distanceToRO = distRO - hit.localPosition().z();
410 }
411 MdtDigiToolInput digiInput(std::abs(driftRadius), distanceToRO, 0., 0., 0., 0., DigitId);
412 double qcharge = 1.;
413 double qgamma = -9999.;
414
415 if (m_DoQballCharge) {
416 // BSM particles need to be treated specially in digitization because in the default simulation the particle gamma and charge are set to the SM muon values
417 // For heavy or multi-charged BSM particles the qgamma and QE are required as inputs to obtain the correct MDT ADC counts
418 const HepMcParticleLink trkParticle = HepMcParticleLink::getRedirectedLink(hit.particleLink(),phit.eventId(), ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
419 HepMC::ConstGenParticlePtr genParticle = trkParticle.cptr();
420 if (genParticle) {
421 if ( MC::isBSM(genParticle) ) {
422 const double QE = genParticle->momentum().e();
423 const double QM2 = genParticle->momentum().m2();
424 if (QM2 >= 0.) {
425 qgamma = QE / std::sqrt(QM2);
426 }
427 }
428 qcharge = MC::fractionalCharge(genParticle);
429 }
430 digiInput = MdtDigiToolInput{std::abs(driftRadius), distanceToRO, 0., 0., qcharge, qgamma, DigitId};
431 }
432
433 // digitize input
434 MdtDigiToolOutput digiOutput(m_digiTool->digitize(ctx, digiInput, toolRndmEngine));
435 //-Implementation for RT_Relation_DB_Tool
436
437 // simulate tube response, check if tube fired
438
439 if (digiOutput.wasEfficient()) {
440 double driftTime = digiOutput.driftTime();
441 double adc = digiOutput.adc();
442
443 ATH_MSG_VERBOSE("Tube efficient: driftTime " << driftTime << " adc value " << adc);
444
445 if (m_useProp) {
446 double position_along_wire = hit.localPosition().z();
447 if (m_useDeformations) { position_along_wire = newSimhit.localPosition().z(); }
448
449 // prop delay calculated with respect to the center of the tube
450 double sign(-1.);
451 if (distRO < 0.) sign = 1.;
452 double propagation_delay = sign * (1. / m_signalSpeed) * position_along_wire;
453 //------------------------------------------------------------
454 // calculate propagation delay, as readout side the side with
455 // negative local
456 // position along the wire is taken
457
458 driftTime += propagation_delay; // add prop time
459 ATH_MSG_VERBOSE("Position along wire: " << position_along_wire << " propagation delay: " << propagation_delay
460 << " new driftTime " << driftTime);
461 }
462
463 // add tof + bunch time
464 if (m_useTof) {
465 driftTime += globalHitTime;
466 ATH_MSG_VERBOSE("Time off Flight + bunch offset: " << globalHitTime << " new driftTime " << driftTime);
467 }
468 ATH_MSG_DEBUG(m_idHelperSvc->mdtIdHelper().show_to_string(DigitId)
469 << " Drift time computation " << driftTime << " radius " << driftRadius << " adc " << adc);
470
471 // add hit to hit collection
472 m_hits.insert(mdt_hit_info(DigitId, driftTime, adc, driftRadius, &phit));
473 ATH_MSG_VERBOSE(" handleMDTSimHit() phit-" << &phit << " hit.localPosition().z() = " << hit.localPosition().z()
474 << " driftRadius = " << driftRadius);
475
476 // + TWIN TUBES (A. Koutsman)
477 if (m_useTwin) {
478 // two chambers in ATLAS are installed with Twin Tubes; in detector coordinates BOL4A13 & BOL4C13; only INNER multilayer(=1) is
479 // with twin tubes
480 bool BOL4X13 = false;
481 // find these two chambers in identifier scheme coordinates as in MdtIdHelper
482 if (stationName == "BOL" && std::abs(stationEta) == 4 && stationPhi == 7 && multilayer == 1) { BOL4X13 = true; }
483
484 // implement twin tubes digitizing either for all BOL (m_useAllBOLTwin = true) _OR_ only for two chambers really installed
485 if ((m_useAllBOLTwin && stationName == "BOL") || BOL4X13) {
486 int twin_tube = 0;
487 Identifier twin_DigitId{0};
488 double twin_sign_driftTime = 0.;
489 // twinpair is connected via a HV-jumper with a delay of ~6ns
490 constexpr double HV_delay = 6.;
491 double twin_tubeLength{0.}, twin_geo_pos_along_wire{0.},
492 twin_sign_pos_along_wire{0.}, twin_sign{-1.};
493
494 // twinpair is interconnected with one tube in between, so modulo 4 they are identical
495 if (tube % 4 == 1 || tube % 4 == 2)
496 twin_tube = tube + 2;
497 else if (tube % 4 == 0 || tube % 4 == 3)
498 twin_tube = tube - 2;
499 // construct Atlas identifier from components for the twin
500 twin_DigitId = m_idHelperSvc->mdtIdHelper().channelID(stationName, stationEta, stationPhi, multilayer, layer, twin_tube);
501 // get twin tube length for propagation delay
502 twin_tubeLength = element->tubeLength(twin_DigitId);
503
504 // prop delay calculated with respect to the center of the tube
505 if (distRO < 0.) twin_sign = 1.;
506 twin_geo_pos_along_wire = hit.localPosition().z();
507 if (m_useDeformations) { twin_geo_pos_along_wire = newSimhit.localPosition().z(); }
508 twin_sign_pos_along_wire = twin_sign * twin_geo_pos_along_wire;
509 double twin_propagation_delay = twin_sign * (1. / m_signalSpeed) * twin_geo_pos_along_wire;
510
511 // calculate drift-time for twin from prompt driftTime + propagation delay + length of tube + hv-delay
512 // ( -2* for propagation_delay, cause prop_delay already in driftTime)
513 twin_sign_driftTime = driftTime + twin_tubeLength / m_signalSpeed - 2 * twin_propagation_delay + HV_delay;
514
515 // smear the twin time by a gaussian with a stDev given by m_resTwin
516 double rand = CLHEP::RandGaussZiggurat::shoot(twinRndmEngine, twin_sign_driftTime, m_resTwin);
517 twin_sign_driftTime = rand;
518
519 ATH_MSG_DEBUG(" TWIN TUBE stname " << stationName << " steta " << stationEta << " stphi " << stationPhi << " mLayer "
520 << multilayer << " layer " << layer << " tube " << tube
521 << " signed position along wire = " << twin_sign_pos_along_wire
522 << " propagation delay = " << twin_propagation_delay << " drifttime = " << driftTime
523 << " twin_driftTime = " << twin_sign_driftTime
524 << " TWIN time-difference = " << (twin_sign_driftTime - driftTime));
525
526 // add twin-hit to hit collection
527 m_hits.insert(mdt_hit_info(twin_DigitId, twin_sign_driftTime, adc, driftRadius, &phit));
528
529 } // end select all BOLs or installed chambers
530 } // end if(m_useTwin){
531 // - TWIN TUBES (A. Koutsman)
532 } else {
533 ATH_MSG_DEBUG(m_idHelperSvc->mdtIdHelper().show_to_string(DigitId) << " Tube not efficient "
534 << " radius " << driftRadius);
535 }
536
537 return true;
538}
539
540bool MdtDigitizationTool::checkMDTSimHit(const EventContext& ctx, const MDTSimHit& hit) const {
541 // get the hit Identifier and info
542 const int id = hit.MDTid();
543 std::string stationName = m_muonHelper->GetStationName(id);
544 int stationEta = m_muonHelper->GetZSector(id);
545 int stationPhi = m_muonHelper->GetPhiSector(id);
546 int multilayer = m_muonHelper->GetMultiLayer(id);
547 int layer = m_muonHelper->GetLayer(id);
548 int tube = m_muonHelper->GetTube(id);
549
550 Identifier DigitId = m_idHelperSvc->mdtIdHelper().channelID(stationName, stationEta, stationPhi, multilayer, layer, tube);
551 ATH_MSG_DEBUG("Working on hit: " << m_idHelperSvc->mdtIdHelper().show_to_string(DigitId) << " "
552 << m_idHelperSvc->mdtIdHelper().stationNameString(m_idHelperSvc->mdtIdHelper().stationName(DigitId))
553 << " " << stationEta << " " << stationPhi);
554
555 //+MASKING OF DEAD/MISSING CHAMBERS
556 if (!m_readKey.empty()) {
558 if (!readCdo.isValid()) {
559 ATH_MSG_WARNING(m_readKey.fullKey() << " is not available.");
560 return false;
561 }
562 if (!readCdo->isGood(DigitId)) return false;
563 }
564 //-MASKING OF DEAD/MISSING CHAMBERS
565
566 double tubeL{0.}, tubeR{0.};
567 const MuonGM::MdtReadoutElement* element = m_MuonGeoMgr->getMdtReadoutElement(DigitId);
568
569 if (!element) {
570 ATH_MSG_ERROR("MuonGeoManager does not return valid element for given id!");
571 } else {
572 tubeL = element->tubeLength(DigitId);
573 tubeR = element->innerTubeRadius();
574 }
575
576 bool ok(true);
577
578 if (std::abs(hit.driftRadius()) > tubeR) {
579 ok = false;
580 ATH_MSG_DEBUG("MDTSimHit has invalid radius: " << hit.driftRadius() << " tubeRadius " << tubeR);
581 }
582
583 if (std::abs(hit.localPosition().z()) > 0.5 * tubeL) {
584 ok = false;
585 ATH_MSG_DEBUG("MDTSimHit has invalid position along tube: " << hit.localPosition().z() << " tubeLength " << tubeL);
586 }
587
588 if (m_useTof) {
589 double minTof = minimumTof(DigitId, m_MuonGeoMgr);
590 if ((hit.globalTime() < 0 || hit.globalTime() > 10 * minTof) && m_DiscardEarlyHits) {
591 ok = false;
592 ATH_MSG_DEBUG("MDTSimHit has invalid global time: " << hit.globalTime() << " minimum Tof " << minTof);
593 }
594 } else {
595 ATH_MSG_DEBUG("MDTSimHit global time: " << hit.globalTime() << " accepted anyway as UseTof is false");
596 }
597
598 return ok;
599}
600
601bool MdtDigitizationTool::createDigits(const EventContext& ctx, Collections_t& collections,
602 MuonSimDataCollection* sdoContainer,
603 CLHEP::HepRandomEngine* rndmEngine) {
604 Identifier currentDigitId{0}, currentElementId{0};
605
606 double currentDeadTime = 0.;
607 MdtDigitCollection* digitCollection = nullptr;
608 // loop over sorted hits
609 m_hits.sort();
610 HitIt it = m_hits.begin();
611
612 // +For Cosmics add
613 double timeOffsetEvent = 0.0;
614 double timeOffsetTotal = 0.0;
615
616 // this offset emulates the timing spead of cosmics: +/- 1 BC
617 if (m_useTof == false && m_useOffSet2 == true) {
618 int inum = CLHEP::RandFlat::shootInt(rndmEngine, 0, 10);
619 if (inum == 8) {
620 timeOffsetEvent = -25.0;
621 } else if (inum == 9) {
622 timeOffsetEvent = 25.0;
623 }
624 ATH_MSG_DEBUG("Emulating timing spead of cosmics: +/- 1 BC. Adding " << timeOffsetEvent << " ns to time");
625 }
626 //-ForCosmics
627
629 if (!mdtCalibConstants.isValid()) {
630 ATH_MSG_FATAL("Failed to retrieve set of calibration constants "<<mdtCalibConstants.fullKey());
631 return false;
632 }
633 for (; it != m_hits.end(); ++it) {
634 Identifier idDigit = it->id;
635 Identifier elementId = m_idHelperSvc->mdtIdHelper().elementID(idDigit);
636 const MuonGM::MdtReadoutElement* geo = m_MuonGeoMgr->getMdtReadoutElement(idDigit);
637
638 // Check if we are in a new chamber, if so get the DigitCollection
639 if (elementId != currentElementId) {
640 currentElementId = elementId;
641 digitCollection = getDigitCollection(elementId, collections);
642
643 //+ForCosmics
644 // this offset emulates the time jitter of cosmic ray muons w.r.t LVL1 accept
645 if (m_useTof == false && m_useOffSet1 == true) {
646 timeOffsetTotal = timeOffsetEvent + CLHEP::RandFlat::shoot(rndmEngine, -12.5, 12.5);
647 ATH_MSG_DEBUG("Emulating time jitter of cosmic ray muons w.r.t LVL1 accept. Adding " << timeOffsetTotal << " ns to time");
648 }
649 //-ForCosmics
650 }
651 if (!digitCollection) {
652 ATH_MSG_ERROR("Trying to use nullptr digitCollection");
653 return false;
654 }
655
656 float driftRadius = it->radius;
657 double driftTime = it->time;
658 double charge = it->adc;
659
660 ATH_MSG_VERBOSE("New hit : driftTime " << driftTime << " adc " << charge);
661
662 // check if we are in a new tube
663 if (idDigit != currentDigitId) {
664 currentDigitId = idDigit;
665 // set the deadTime
666 currentDeadTime = driftTime + charge + m_deadTime;
667 ATH_MSG_VERBOSE("New tube, setting dead time: " << currentDeadTime << " driftTime " << driftTime);
668 } else {
669 // check if tube is dead
670 if (driftTime > currentDeadTime) {
671 // tube produces a second hit, set the new deadtime
672 currentDeadTime = driftTime + charge + m_deadTime;
673 ATH_MSG_VERBOSE("Additional hit, setting dead time: " << currentDeadTime << " driftTime " << driftTime);
674 } else {
675 // tube is dead go to next hit
676 ATH_MSG_VERBOSE("Hit within dead time: " << currentDeadTime << " driftTime " << driftTime);
677 continue;
678 }
679 }
680
681 const TimedHitPtr<MDTSimHit>& phit = *(it->simhit);
682 const MDTSimHit& hit(*phit);
683
684 // check if the hits lies within the TDC time window
685 // subtrack the minimum Tof (= globalPosition().mag()/c) from the tof of the hit
686 double relativeTime = driftTime - minimumTof(idDigit, m_MuonGeoMgr);
687 bool insideMatch = insideMatchingWindow(relativeTime);
688 bool insideMask = insideMaskWindow(relativeTime);
689 if (insideMask && insideMatch) {
690 ATH_MSG_WARNING(" Digit in matching AND masking window, please check window definition: relative time " << relativeTime);
691 insideMask = false;
692 }
693 if (insideMatch || insideMask) {
694 // get calibration constants from DbTool
695 double t0 = m_offsetTDC;
696 const MuonCalib::MdtFullCalibData* data{mdtCalibConstants->getCalibData(idDigit, msgStream())};
697 if (data && data->tubeCalib) {
698 // extract calibration constants for single tube
699 const MuonCalib::MdtTubeCalibContainer::SingleTubeCalib* singleTubeData = data->tubeCalib->getCalib(idDigit);
700 if (singleTubeData) {
701 ATH_MSG_DEBUG("Extracted the following calibration constant for "<<m_idHelperSvc->toString(idDigit)<<" "<<singleTubeData->t0);
702 t0 = singleTubeData->t0 + m_t0ShiftTuning;
703 } else ATH_MSG_WARNING("No calibration data found, using t0=" << m_offsetTDC<<" "<<m_idHelperSvc->toString(idDigit));
704 } else {
705 ATH_MSG_WARNING("No calibration data found, using t0=" << m_offsetTDC<<" for "<<m_idHelperSvc->toString(idDigit));
706 }
707 bool isHPTDC = m_idHelperSvc->hasHPTDC(idDigit);
708 int tdc = digitizeTime(driftTime + t0 + timeOffsetTotal, isHPTDC, rndmEngine);
709 int adc = digitizeTime(it->adc, isHPTDC, rndmEngine);
710 ATH_MSG_DEBUG(" >> Digit Id = " << m_idHelperSvc->mdtIdHelper().show_to_string(idDigit) << " driftTime " << driftTime
711 << " driftRadius " << driftRadius << " TDC " << tdc << " ADC " << adc << " mask bit "
712 << insideMask);
713
714 MdtDigit* newDigit = new MdtDigit(idDigit, tdc, adc, insideMask);
715 digitCollection->push_back(newDigit);
716
717 ATH_MSG_VERBOSE(" createDigits() phit-" << &phit << " hit-" << hit.print() << " localZPos = " << hit.localPosition().z());
718
719 // Do not store pile-up truth information
720 if (!m_includePileUpTruth && HepMC::ignoreTruthLink(phit->particleLink(), m_vetoPileUpTruthLinks)) { continue; }
721
722 // Create the Deposit for MuonSimData
723 MuonSimData::Deposit deposit(HepMcParticleLink::getRedirectedLink(phit->particleLink(), phit.eventId(), ctx), // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
724 MuonMCData(driftRadius, hit.localPosition().z()));
725
726 // Record the SDO collection in StoreGate
727 std::vector<MuonSimData::Deposit> deposits;
728 deposits.push_back(deposit);
729 MuonSimData tempSDO(deposits, 0);
730 const Amg::Vector3D& tempLocPos = (*(it->simhit))->localPosition();
731 Amg::Vector3D p = geo->localToGlobalTransf(idDigit)*tempLocPos;
732 tempSDO.setPosition(p);
733 tempSDO.setTime(hitTime(phit));
734 sdoContainer->insert(std::make_pair(idDigit, tempSDO));
735
736 } else {
737 ATH_MSG_DEBUG(" >> OUTSIDE TIME WINDOWS << "
738 << " Digit Id = " << m_idHelperSvc->toString(idDigit) << " driftTime " << driftTime
739 << " --> hit ignored");
740 }
741 } // for (; it != hits.end(); ++it)
742
743 return true;
744}
745
747 IdContext mdtContext = m_idHelperSvc->mdtIdHelper().module_context();
748 IdentifierHash coll_hash;
749 if (m_idHelperSvc->mdtIdHelper().get_hash(elementId, coll_hash, &mdtContext)) {
750 ATH_MSG_ERROR("Unable to get MDT hash id from MDT Digit collection "
751 << "context begin_index = " << mdtContext.begin_index() << " context end_index = " << mdtContext.end_index()
752 << " the identifier is ");
753 elementId.show();
754 }
755
756 if (coll_hash >= collections.size()) {
757 collections.resize (coll_hash+1);
758 }
759
760 auto& coll = collections[coll_hash];
761 if (!coll) {
762 coll = std::make_unique<MdtDigitCollection>(elementId, coll_hash);
763 }
764 return coll.get();
765}
766
767int MdtDigitizationTool::digitizeTime(double time, bool isHPTDC, CLHEP::HepRandomEngine* rndmEngine) const {
768 int tdcCount{0};
769 double tmpCount = isHPTDC ? time / m_ns2TDCHPTDC : time / m_ns2TDCAMT;
770 tdcCount = CLHEP::RandGaussZiggurat::shoot(rndmEngine, tmpCount, m_resTDC);
771 if (tdcCount < 0 || tdcCount > 4096) { ATH_MSG_DEBUG(" Count outside TDC window: " << tdcCount); }
772 return tdcCount;
773}
774
776 if (!m_useTof) return 0.;
777
778 // get distance to vertex for tof correction before applying the time window
779 double distanceToVertex(0.);
780 const MuonGM::MdtReadoutElement* element = detMgr->getMdtReadoutElement(DigitId);
781
782 if (!element) {
783 ATH_MSG_ERROR("MuonGeoManager does not return valid element for given id!");
784 } else {
785 distanceToVertex = element->tubePos(DigitId).mag();
786 }
787 // what about this? does this also need to be 1/m_signalSpeed ?
788 ATH_MSG_DEBUG("minimumTof calculated " << distanceToVertex * s_inv_c_light);
789 return distanceToVertex * s_inv_c_light;
790}
791
793 if (m_useTimeWindow)
794 if (time < m_bunchCountOffset || time > static_cast<double>(m_bunchCountOffset) + m_matchingWindow) {
795 ATH_MSG_VERBOSE("hit outside MatchingWindow " << time);
796 return false;
797 }
798 return true;
799}
800
802 if (m_useTimeWindow)
803 if (time < static_cast<double>(m_bunchCountOffset) - m_maskWindow || time > m_bunchCountOffset) {
804 ATH_MSG_VERBOSE("hit outside MaskWindow " << time);
805 return false;
806 }
807 return true;
808}
809
810//+emulate deformations here
812 const Identifier& DigitId) {
813 // make the deformation
814 Amg::Vector3D hitAtGlobalFrame = element->nodeform_localToGlobalTransf(DigitId) * hit.localPosition();
815 Amg::Vector3D hitDeformed = element->globalToLocalTransf(DigitId) * hitAtGlobalFrame;
816 MDTSimHit simhit2(hit);
817 // apply the deformation
818 simhit2.setDriftRadius(hitDeformed.perp());
819 simhit2.setLocalPosition(hitDeformed);
820 return simhit2;
821}
822
824 const MuonGM::MdtReadoutElement* element) const {
825 Amg::Vector3D lpos = hit.localPosition();
826 Amg::Transform3D gToWireFrame = element->globalToLocalTransf(id);
827
828 // local track direction in precision plane
829 Amg::Vector3D ldir(-lpos.y(), lpos.x(), 0.);
830 ldir.normalize();
831
832 // calculate the position of the hit sagged wire frame
833 // transform to global coords
834 const Amg::Transform3D& transf{element->localToGlobalTransf(id)};
835 Amg::Vector3D gpos = transf*lpos;
836 Amg::Vector3D gdir = transf* ldir;
837
838 // get wire surface
839 const Trk::StraightLineSurface& surface = element->surface(id);
840
841 // check whether direction is pointing away from IP
842 double pointingCheck = gpos.dot(gdir) < 0 ? -1. : 1.;
843 if (pointingCheck < 0) { gdir *= pointingCheck; }
844
845 double trackingSign = 1.;
846 double localSag = 0.0;
847
848 // recalculate tracking sign
849 Amg::Vector2D lpsag{Amg::Vector2D::Zero()};
850 surface.globalToLocal(gpos, gdir, lpsag);
851 trackingSign = lpsag[Trk::locR] < 0 ? -1. : 1.;
852
853
854 // local gravity vector
855 Amg::Vector3D gravityDir =-1. * Amg::Vector3D::UnitY();
856 Amg::Vector3D lgravDir = gToWireFrame * gravityDir;
857
858 // Project gravity vector onto X-Y plane, so the z-components (along the wire)
859 // don't contribute to the dot-product.
860 lgravDir.z() = 0.;
861
862 // calculate whether hit above or below wire (using gravity direction
863 // 1 -> hit below wire (in same hemisphere as gravity vector)
864 //-1 -> hit above wire (in opposite hemisphere as gravity vector)
865 double sign = lpos.dot(lgravDir) < 0 ? -1. : 1.;
866
867 return {sign, trackingSign, lpos, localSag};
868}
float hitTime(const AFP_SIDSimHit &hit)
#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)
double charge(const T &p)
Definition AtlasPID.h:997
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
ATLAS-specific HepMC functions.
std::vector< xAOD::EventInfo::SubEvent >::const_iterator SubEventIterator
Definition IPileUpTool.h:22
static Double_t t0
AtlasHitsVector< MDTSimHit > MDTSimHitCollection
HitVector::iterator HitIt
int sign(int a)
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:169
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:134
size_type size() const
value_type push_back(value_type pElem)
Add an element to the end of the collection.
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
This is a "hash" representation of an Identifier.
void show() const
Print out in hex form.
void setLocalPosition(Amg::Vector3D &localPosition)
Definition MDTSimHit.h:55
const Amg::Vector3D & localPosition() const
Definition MDTSimHit.h:54
void setDriftRadius(double radius)
Definition MDTSimHit.h:52
double driftRadius() const
Definition MDTSimHit.h:51
HitID MDTid() const
Definition MDTSimHit.h:62
const HepMcParticleLink & particleLink() const
Definition MDTSimHit.h:100
std::string print() const
double globalTime() const
Definition MDTSimHit.h:48
double driftTime() const
double wasEfficient() const
SG::ReadCondHandleKey< MuonCalib::MdtCalibDataContainer > m_calibDbKey
std::vector< std::unique_ptr< MdtDigitCollection > > Collections_t
SG::ReadHandleKey< MDTSimHitCollection > m_hitsContainerKey
StatusCode mergeEvent(const EventContext &ctx) override final
When being run from PileUpToolsAlgs, this method is called at the end of the subevts loop.
bool handleMDTSimHit(const EventContext &ctx, const TimedHitPtr< MDTSimHit > &phit, CLHEP::HepRandomEngine *twinRndmEngine, CLHEP::HepRandomEngine *toolRndmEngine)
CLHEP::HepRandomEngine * getRandomEngine(const std::string &streamName, const EventContext &ctx) const
double minimumTof(Identifier DigitId, const MuonGM::MuonDetectorManager *detMgr) const
static MDTSimHit applyDeformations(const MDTSimHit &, const MuonGM::MdtReadoutElement *, const Identifier &)
bool createDigits(const EventContext &ctx, Collections_t &collections, MuonSimDataCollection *sdoContainer, CLHEP::HepRandomEngine *rndmEngine)
std::unique_ptr< TimedHitCollection< MDTSimHit > > m_thpcMDT
MdtDigitCollection * getDigitCollection(Identifier elementId, Collections_t &collections)
bool checkMDTSimHit(const EventContext &ctx, const MDTSimHit &hit) const
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 ...
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.
StatusCode doDigitization(const EventContext &ctx, Collections_t &collections, MuonSimDataCollection *sdoContainer)
int digitizeTime(double time, bool isHPTDC, CLHEP::HepRandomEngine *rndmEngine) const
SG::WriteHandleKey< MdtDigitContainer > m_outputObjectKey
MdtDigitizationTool(const std::string &type, const std::string &name, const IInterface *pIID)
virtual StatusCode initialize() override final
Initialize.
GeoCorOut correctGeometricalWireSag(const MDTSimHit &hit, const Identifier &id, const MuonGM::MdtReadoutElement *element) const
SG::WriteHandleKey< MuonSimDataCollection > m_outputSDOKey
virtual StatusCode processAllSubEvents(const EventContext &ctx) override final
alternative interface which uses the PileUpMergeSvc to obtain all the required SubEvents.
static const MdtHitIdHelper * GetHelper(unsigned int nTubes=78)
Amg::Vector3D tubePos(const Identifier &id) const
Returns the global position of the given tube.
Amg::Transform3D nodeform_localToGlobalTransf(const Identifier &id) const
Amg::Vector3D tubeFrame_localROPos(const int tubelayer, const int tube) const
virtual const Trk::Surface & surface() const override final
Return surface associated with this detector element.
double innerTubeRadius() const
Returns the inner tube radius excluding the aluminium walls.
const Amg::Transform3D & localToGlobalTransf(const Identifier &id) const
double tubeLength(const int tubeLayer, const int tube) const
Amg::Transform3D globalToLocalTransf(const int tubeLayer, const int tube) const
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const MdtReadoutElement * getMdtReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
void setTime(const float &time)
std::pair< HepMcParticleLink, MuonMCData > Deposit
Definition MuonSimData.h:66
void setPosition(const Amg::Vector3D &pos)
Gaudi::Property< int > m_vetoPileUpTruthLinks
PileUpToolBase(const std::string &type, const std::string &name, const IInterface *parent)
const DataObjID & fullKey() const
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
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for StraightLineSurface: GlobalToLocal method without dynamic memory allocation This method...
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
const GenParticle * ConstGenParticlePtr
Definition GenParticle.h:38
bool ignoreTruthLink(const T &p, bool vetoPileUp)
Helper function for SDO creation in PileUpTools.
double fractionalCharge(const T &p)
bool isBSM(const T &p)
APID: graviton and all Higgs extensions are BSM.
@ locR
Definition ParamDefs.h:44
class which holds the full set of calibration constants for a given tube
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