413 {
415
417 if (!muonGeoMgrHandle.
isValid()) {
418 ATH_MSG_FATAL(
"Failed to retrieve the detector manager from the conditiosn store");
419 return StatusCode::FAILURE;
420 }
421 const MuonGM::MuonDetectorManager* muonGeoMgr = *muonGeoMgrHandle;
422
423
425 ATH_CHECK(digitContainer.record(std::make_unique<MmDigitContainer>(
m_idHelperSvc->mmIdHelper().detectorElement_hash_max())));
427
428
430 ATH_CHECK(sdoContainer.record(std::make_unique<MuonSimDataCollection>()));
432
433
435
436
439 return StatusCode::FAILURE;
440 }
441
442
443
445
446 std::vector<std::unique_ptr<MmDigitCollection> > collections;
447
448
451 Identifier layerID;
452 std::vector<MM_ElectronicsToolInput> v_stripDigitOutput;
453
454
455 while (i != e) {
457
458
459
460 TimedHitPtr<MMSimHit> phit = *
i++;
461 const double eventTime = phit.
eventTime();
462 const MMSimHit& hit(*phit);
463
464 const double hitKineticEnergy = hit.kineticEnergy();
465 if (hitKineticEnergy <= 0) continue;
466
467 const Amg::Vector3D& globalHitPosition = hit.globalPosition();
468
469 const double globalHitTime = hit.globalTime();
470 const double tofCorrection = globalHitPosition.mag() / CLHEP::c_light;
471 const double bunchTime = globalHitTime - tofCorrection + eventTime;
472
473 const int hitID = hit.MMId();
474
475
476
477
478
479 MM_SimIdToOfflineId simToOffline(&idHelper);
480
481
482 int simId = hit.MMId();
483 layerID = simToOffline.convert(simId);
484
487 bool acceptHit = true;
489 if (!acceptHit) {
491 continue;
492 }
493 }
495
496 ATH_MSG_DEBUG(
"> hitID " << hitID <<
" Hit bunch time " << bunchTime <<
" tot " << globalHitTime <<
" tof/G4 time "
497 << hit.globalTime() << " globalHitPosition " << globalHitPosition << "hit: r "
498 << globalHitPosition.perp() << " z " << globalHitPosition.z() << " mclink " << particleLink
500
501
502
503
505
506
507
508
510
512
513
514
517 continue;
518 }
519
520
521 const MuonGM::MMReadoutElement* detectorReadoutElement = muonGeoMgr->
getMMReadoutElement(layerID);
522 if (!detectorReadoutElement) {
524 continue;
525 }
526 const std::array<int, 4>& readoutSide=detectorReadoutElement->
getReadoutSide();
527
528
529
530
532
534
535
537
538
539
540
541
542 const Trk::PlaneSurface& surf = detectorReadoutElement->
surface(layerID);
543
544
545
546 const Amg::Vector3D globalHitDirection = hit.globalDirection();
547 Trk::LocalDirection localHitDirection;
549
550
551
552 float inAngleCompliment_XZ = localHitDirection.
angleXZ() / CLHEP::degree;
553 float inAngleCompliment_YZ = localHitDirection.
angleYZ() / CLHEP::degree;
554
555
556 if (inAngleCompliment_XZ < 0.0) inAngleCompliment_XZ += 180;
557 if (inAngleCompliment_YZ < 0.0) inAngleCompliment_YZ += 180;
558
559
560 float inAngle_XZ = 90. - inAngleCompliment_XZ;
561 float inAngle_YZ = 90. - inAngleCompliment_YZ;
562
564 <<
" Readout Side: " << (readoutSide).at(
m_muonHelper->GetLayer(simId) - 1)
565 <<
" Layer: " <<
m_muonHelper->GetLayer(simId) <<
"\n\t\t\t inAngle_XZ (degrees): " << inAngle_XZ
566 << " inAngle_YZ (degrees): " << inAngle_YZ);
567
568
570 Amg::Vector2D positionOnSurfaceUnprojected{stripLayerPosition.x(), stripLayerPosition.y()};
571
574
575
576 if ((readoutSide).at(idHelper.
gasGap(layerID) - 1) == 1) {
577 localDirectionTime = localDirection;
578 inAngle_XZ = (-inAngle_XZ);
579 } else
580 localDirectionTime = surf.
transform().inverse().linear() * globalHitDirection;
581
586 if (gasGap == 1 || gasGap == 3) {
587 scale = -(stripLayerPosition.z() + shift) / localDirection.z();
588 } else if (gasGap == 2 || gasGap == 4) {
589 scale = -(stripLayerPosition.z() - shift) / localDirection.z();
590 }
591
593 Amg::Vector2D positionOnSurface{hitOnSurface.x(), hitOnSurface.y()};
594
595
597 Amg::Vector3D hitAfterTimeShift(hitOnSurface.x(), hitOnSurface.y(), shiftTimeOffset);
598 Amg::Vector3D hitAfterTimeShiftOnSurface = hitAfterTimeShift - (shiftTimeOffset / localDirectionTime.z()) * localDirectionTime;
599
600 if (std::abs(hitAfterTimeShiftOnSurface.z()) > 0.1)
601 ATH_MSG_WARNING(
"Bad propagation to surface after time shift " << hitAfterTimeShiftOnSurface);
602
603
604 double scaleSDO = -stripLayerPosition.z() / localDirection.z();
605 Amg::Vector3D hitAtCenterOfGasGap = stripLayerPosition + scaleSDO * localDirection;
607 ATH_MSG_DEBUG(
"strip layer position z" << stripLayerPosition.z() <<
"hitAtCenterOfGasGap "
608 <<
Amg::toString(hitAtCenterOfGasGap)<<
" gas gap " << gasGap);
609
610
611 if (hit.kineticEnergy() <
m_energyThreshold && std::abs(hit.particleEncoding()) == 11) {
612 continue;
613 }
614
615
618 continue;
619 }
620
621 int stripNumber = detectorReadoutElement->
stripNumber(positionOnSurface, layerID);
623
624 if (stripNumber == -1) {
626 <<
m_idHelperSvc->mmIdHelper().print_to_string(layerID) <<
"\n\t\t with pos " << positionOnSurface <<
" z "
627 << stripLayerPosition.z() << " eKin: " << hit.kineticEnergy() << " eDep: " << hit.depositEnergy()
628 <<
" unprojectedStrip: " << detectorReadoutElement->
stripNumber(positionOnSurfaceUnprojected, layerID));
629 continue;
630 }
631
632
633 Identifier parentID = idHelper.
parentID(layerID);
634 Identifier digitID = idHelper.
channelID(parentID,
636 idHelper.
gasGap(layerID), stripNumber);
637
638
639 const IdentifierHash moduleHash =
m_idHelperSvc->moduleHash(layerID);
640
642 <<
static_cast<int>(moduleHash) <<
" " <<
m_idHelperSvc->toString(layerID)
644
645 const MuonGM::MuonChannelDesign* mmChannelDesign = detectorReadoutElement->
getDesign(digitID);
646 double distToChannel = mmChannelDesign->
distanceToChannel(positionOnSurface, stripNumber);
647
648
649
650 int geoStripNumber = mmChannelDesign->
channelNumber(positionOnSurface);
651 if (geoStripNumber == -1)
ATH_MSG_WARNING(
"Failed to retrieve strip number");
652
654 if (!mmChannelDesign->
center(geoStripNumber, chPos)) {
655 ATH_MSG_DEBUG(
"Failed to retrieve channel position for closest strip number "
656 << geoStripNumber
657 << ". Can happen if hit was found in non-active strip. Will not digitize it, since in data, "
658 << "we would probably not find a cluster formed well enough to survive reconstruction.");
659 continue;
660 }
661
662 MagField::AtlasFieldCache fieldCache;
664 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
665 if (!fieldCondObj) {
667 return StatusCode::FAILURE;
668 }
670
671
674 fieldCache.
getField(hitOnSurfaceGlobal.data(), magneticField.data());
675
676
678 if ((readoutSide).at(
m_muonHelper->GetLayer(simId) - 1) == -1)
679 localMagneticField[
Amg::y] = -localMagneticField[
Amg::y];
680
681
682
683
685
687
688
689
690 const MM_DigitToolInput stripDigitInput(
691 stripNumber, distToChannel, inAngle_XZ, inAngle_YZ, localMagneticField,
694 idHelper.
gasGap(layerID), eventTime + globalHitTime);
695
696
697
698
699
700
701
702
704
705
706 std::vector<MuonSimData::Deposit> deposits{deposit};
707 MuonSimData
simData(std::move(deposits), 0);
708 simData.setPosition(hitAtCenterOfGasGapGlobal);
709 simData.setTime(globalHitTime);
710 sdoContainer->insert(std::make_pair(digitID,
simData));
712
713 float gainFraction = 1.0;
715
716 Identifier
id = idHelper.
channelID(layerID,
718 idHelper.
gasGap(layerID), stripNumber);
720 }
722
723 MM_StripToolOutput tmpStripOutput =
m_StripsResponseSimulation->GetResponseFrom(stripDigitInput, gainFraction, stripPitch, rndmEngine);
725 tmpStripOutput.
chipTime(), digitID, hit.kineticEnergy());
726
727 v_stripDigitOutput.push_back(stripDigitOutput);
728
729 }
730
731
732
733 if (v_stripDigitOutput.empty()) {
734 ATH_MSG_DEBUG(
"MM_DigitizationTool::doDigitization() -- there is no strip response on this VMM.");
735 continue;
736 }
737
739
740
741
742
743
744
749 << " is not a MM Identifier, skipping");
750 continue;
751 }
752
753
754
755
759 if (!electronicsOutputForReadout.
isValid()) {
761 " there is no electronics response (peak finding mode) even though there is a strip response.");
762 }
763
764
765 for (
unsigned int firedCh = 0; firedCh < electronicsOutputForReadout.
stripPos().size(); ++firedCh) {
766
768 float time = electronicsOutputForReadout.
stripTime()[firedCh];
771 const Identifier digitID = idHelper.
channelID(stripDigitOutputAllHits.
digitID(),
777 continue;
778 }
779 bool acceptStrip = true;
783
784 }
785 if (!acceptStrip) {
787 continue;
788 }
789 std::unique_ptr<MmDigit> newDigit = std::make_unique<MmDigit>(digitID, time,
charge);
790
791 const IdentifierHash moduleHash =
m_idHelperSvc->moduleHash(digitID);
792 if (moduleHash >= collections.size()) {
793 collections.resize(moduleHash+1);
794 }
795 MmDigitCollection* coll = collections[moduleHash].get();
796 if (!coll) {
797 collections[moduleHash] = std::make_unique<MmDigitCollection>(
m_idHelperSvc->chamberId(digitID), moduleHash);
798 coll = collections[moduleHash].get();
799 }
801 }
802 v_stripDigitOutput.clear();
803 }
804
805 for (size_t coll_hash = 0; coll_hash < collections.size(); ++coll_hash) {
806 if (collections[coll_hash]) {
807 ATH_CHECK( digitContainer->addCollection (collections[coll_hash].release(), coll_hash) );
808 }
809 }
810
812
814
815 return StatusCode::SUCCESS;
816}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
double charge(const T &p)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
static HepMcParticleLink getRedirectedLink(const HepMcParticleLink &particleLink, uint32_t eventIndex, const EventContext &ctx)
Return a HepMcParticleLink pointing at the same particle, but in a different GenEvent.
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
int gasGap(const Identifier &id) const override
get the hashes
Identifier parentID(const Identifier &id) const
int multilayer(const Identifier &id) const
int numberOfMissingTopStrips(const Identifier &layerId) const
Number of missing bottom and top strips (not read out)
const std::array< int, 4 > & getReadoutSide() const
virtual int numberOfStrips(const Identifier &layerId) const override final
number of strips per layer
bool insideActiveBounds(const Identifier &id, const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const
boundary check Wrapper Trk::PlaneSurface::insideBounds() taking into account the passivated width
int numberOfMissingBottomStrips(const Identifier &layerId) const
virtual int stripNumber(const Amg::Vector2D &pos, const Identifier &id) const override final
strip number corresponding to local position.
const MuonChannelDesign * getDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
std::pair< HepMcParticleLink, MuonMCData > Deposit
TimedVector::const_iterator const_iterator
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
float eventTime() const
t0 offset of the bunch xing containing the hit in ns.
double angleXZ() const
access method for angle of local XZ projection
double angleYZ() const
access method for angle of local YZ projection
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
time(flags, cells_name, *args, **kw)
const std::string & stName(StIndex index)
convert StIndex into a string
bool center(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the center on the strip.
double channelWidth() const
calculate local channel width
double distanceToChannel(const Amg::Vector2D &pos, int nChannel) const
distance to channel - residual
int channelNumber(const Amg::Vector2D &pos) const
calculate local channel number, range 1=nstrips like identifiers. Returns -1 if out of range