ATLAS Offline Software
MmSensitiveDetector.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "MmSensitiveDetector.h"
7 #include "G4ThreeVector.hh"
8 #include "G4Trd.hh"
9 #include "G4Geantino.hh"
10 #include "G4ChargedGeantino.hh"
11 
12 #include "MCTruth/TrackHelper.h"
13 #include <sstream>
14 
17 #include "GeoModelHelpers/throwExcept.h"
18 #include "GaudiKernel/SystemOfUnits.h"
19 
20 
21 using namespace MuonGMR4;
22 using namespace CxxUtils;
23 using namespace ActsTrk;
24 
25 namespace {
26  constexpr double tolerance = 10. * Gaudi::Units::micrometer;
27 }
28 
29 // construction/destruction
30 namespace MuonG4R4 {
31 
32 MmSensitiveDetector::MmSensitiveDetector(const std::string& name,
33  const std::string& output_key,
34  const std::string& trf_storeKey,
35  const MuonGMR4::MuonDetectorManager* detMgr):
36  G4VSensitiveDetector{name},
38  m_writeHandle{output_key},
39  m_trfCacheKey{trf_storeKey},
40  m_detMgr{detMgr} {
41  m_trfCacheKey.initialize().ignore();
42 }
43 
44 void MmSensitiveDetector::Initialize(G4HCofThisEvent*) {
45  if (m_writeHandle.isValid()) {
46  ATH_MSG_VERBOSE("Simulation hit container "<<m_writeHandle.fullKey()<<" is already written");
47  return;
48  }
49  if (!m_writeHandle.recordNonConst(std::make_unique<xAOD::MuonSimHitContainer>(),
50  std::make_unique<xAOD::MuonSimHitAuxContainer>()).isSuccess()) {
51  THROW_EXCEPTION("Failed to record "<<m_writeHandle.fullKey());
52  }
53  ATH_MSG_DEBUG("Output container "<<m_writeHandle.fullKey()<<" has been successfully created");
54 }
55 
56 G4bool MmSensitiveDetector::ProcessHits(G4Step* aStep,G4TouchableHistory*) {
57 
58  G4Track* currentTrack = aStep->GetTrack();
59  // MDTs sensitive to charged particle only
60  if (currentTrack->GetDefinition()->GetPDGCharge() == 0.0) {
61  if (currentTrack->GetDefinition()!= G4Geantino::GeantinoDefinition()) return true;
62  else if (currentTrack->GetDefinition()==G4ChargedGeantino::ChargedGeantinoDefinition()) return true;
63  }
64 
66  constexpr double velCutOff = 10.*Gaudi::Units::micrometer / Gaudi::Units::second;
67  if (currentTrack->GetVelocity() < velCutOff) return true;
68 
69  ActsGeometryContext gctx{};
70 
72  if (!trfStoreHandle.isValid()) {
73  ATH_MSG_FATAL("Failed to retrieve "<<m_trfCacheKey.fullKey()<<".");
74  return false;
75  }
76  gctx.setStore(std::make_unique<DetectorAlignStore>(*trfStoreHandle));
77 
78  const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(currentTrack->GetTouchable());
79  const MuonGMR4::MmReadoutElement* readOutEle = getReadoutElement(gctx, touchHist);
80 
81 
82  const Amg::Transform3D globalToLocal = getTransform(touchHist, 0).inverse();
83  ATH_MSG_VERBOSE(" Track is inside volume "
84  << touchHist->GetHistory()->GetTopVolume()->GetName()
85  <<" transformation: "<<Amg::toString(globalToLocal));
86  // transform pre and post step positions to local positions
87 
88  const Amg::Vector3D localPos{globalToLocal*Amg::Hep3VectorToEigen(currentTrack->GetPosition())};
89  const Amg::Vector3D localDir{globalToLocal.linear()*Amg::Hep3VectorToEigen(currentTrack->GetMomentumDirection())};
90  ATH_MSG_VERBOSE("Entry / exit point in "<<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify())
91  <<" "<<Amg::toString(localPos, 2)<<" / "<<Amg::toString(localDir, 2));
92 
93 
94  // The middle of the gas gap is at X= 0
95  std::optional<double> travelDist = Amg::intersect<3>(localPos, localDir, Amg::Vector3D::UnitX(), 0.);
96  if (!travelDist) return true;
97  const Amg::Vector3D locGapCross = localPos + (*travelDist) * localDir;
98  ATH_MSG_VERBOSE("Propagation to the gas gap center: "<<Amg::toString(locGapCross, 2));
99  const Amg::Vector3D gapCenterCross = globalToLocal.inverse() * locGapCross;
100 
101  const Identifier hitID = getIdentifier(gctx, readOutEle, gapCenterCross);
102  if (!hitID.is_valid()) {
103  ATH_MSG_VERBOSE("No valid hit found");
104  return true;
105  }
106  const double globalTime = currentTrack->GetGlobalTime() + (*travelDist) / currentTrack->GetVelocity();
107  const Amg::Transform3D gapTrans{readOutEle->globalToLocalTrans(gctx, hitID)};
108  const Amg::Vector3D locHitDir = gapTrans.linear() * Amg::Hep3VectorToEigen(currentTrack->GetMomentumDirection());
109  const Amg::Vector3D locHitPos = gapTrans * gapCenterCross;
110 
111  xAOD::MuonSimHit* hit = new xAOD::MuonSimHit();
112  m_writeHandle->push_back(hit);
113 
114  TrackHelper trHelp(aStep->GetTrack());
115  hit->setIdentifier(hitID);
116  hit->setLocalPosition(xAOD::toStorage(locHitPos));
117  hit->setLocalDirection(xAOD::toStorage(locHitDir));
118  hit->setMass(currentTrack->GetDefinition()->GetPDGMass());
119  hit->setGlobalTime(globalTime);
120  hit->setPdgId(currentTrack->GetDefinition()->GetPDGEncoding());
121  hit->setEnergyDeposit(aStep->GetTotalEnergyDeposit());
122  hit->setKineticEnergy(currentTrack->GetKineticEnergy());
124  return true;
125 }
126 
128  const MuonGMR4::MmReadoutElement* readOutEle,
129  const Amg::Vector3D& hitAtGapPlane) const {
131  for (unsigned int gap = 1; gap <= readOutEle->nGasGaps(); ++gap){
132  const Amg::Vector3D gapCentre = readOutEle->center(gctx, MmReadoutElement::createHash(gap, 0));
133  ATH_MSG_VERBOSE("Try to match "<<Amg::toString(hitAtGapPlane)<<" to "<<Amg::toString(gapCentre)
134  <<" in "<<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify())<<" dZ: "
135  <<std::abs(gapCentre.z() - hitAtGapPlane.z()));
136  if (std::abs(gapCentre.z() - hitAtGapPlane.z()) < tolerance) {
137  ATH_MSG_VERBOSE("Assign hit "<<Amg::toString(hitAtGapPlane)<<" to "
138  <<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify())<<" gasGap: "<<gap);
139  return readOutEle->measurementId(MmReadoutElement::createHash(gap, 1));
140  }
141  }
142  THROW_EXCEPTION("Invalid gasgap matching for hit "<<Amg::toString(hitAtGapPlane)<<" and detector element "
143  <<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify()));
144  return Identifier{};
145 }
147  const G4TouchableHistory* touchHist) const {
149  const std::string& stationVolume = touchHist->GetVolume(4)->GetName();
151  const std::vector<std::string> volumeTokens = tokenize(stationVolume.substr(stationVolume.rfind("NSW") + 4), "_");
152  ATH_MSG_VERBOSE("Name of the station volume is "<<volumeTokens);
153  if (volumeTokens.size() != 4) {
154  THROW_EXCEPTION(" Cannot deduce the station name from "<<stationVolume);
155  }
157  const std::string stName = volumeTokens[0][0] == 'S' ? "MMS" : "MML";
158  const int stationEta = atoi(volumeTokens[2]);
159  const int stationPhi = atoi(volumeTokens[3]);
160 
161  const MmIdHelper& idHelper{m_detMgr->idHelperSvc()->mmIdHelper()};
162  const Identifier detElIdMl1 = idHelper.channelID(idHelper.stationNameIndex(stName), stationEta, stationPhi, 1, 1, 1);
163  const Identifier detElIdMl2 = idHelper.multilayerID(detElIdMl1, 2);
164  const MmReadoutElement* readOutElemMl1 = m_detMgr->getMmReadoutElement(detElIdMl1);
165  const MmReadoutElement* readOutElemMl2 = m_detMgr->getMmReadoutElement(detElIdMl2);
166  if (!readOutElemMl1 || !readOutElemMl2) {
167  THROW_EXCEPTION(" Failed to retrieve a valid detector element from "
168  <<m_detMgr->idHelperSvc()->toStringDetEl(detElIdMl1)<<" "<<stationVolume);
169  }
171  const Amg::Vector3D transformCenter = getTransform(touchHist, 0).translation();
174  const Amg::Vector3D centerMl2 = readOutElemMl2->center(gctx, detElIdMl2);
175  ATH_MSG_VERBOSE("Local gap position "<<Amg::toString(centerMl2)<<" transform center "<<Amg::toString(transformCenter));
176  return std::abs(centerMl2.z()) - tolerance <= std::abs(transformCenter.z()) ? readOutElemMl2 : readOutElemMl1;
177 }
178 }
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
xAOD::MuonSimHit_v1
Definition: MuonSimHit_v1.h:18
MuonGMR4::MmReadoutElement
Definition: MmReadoutElement.h:20
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
xAOD::MuonSimHit_v1::setIdentifier
void setIdentifier(const Identifier &id)
Sets the global ATLAS identifier.
Definition: xAODMuonSimHit_V1.cxx:43
MuonGMR4::MmReadoutElement::nGasGaps
unsigned int nGasGaps() const
Returns the number of gas gaps.
MmSensitiveDetector.h
MuonGMR4::MuonDetectorManager
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonDetectorManager.h:61
MuonG4R4::MmSensitiveDetector::getIdentifier
Identifier getIdentifier(const ActsGeometryContext &gctx, const MuonGMR4::MmReadoutElement *readOutEle, const Amg::Vector3D &hitAtGapPlane) const
Identify the gasGap layer of the hit.
Definition: MmSensitiveDetector.cxx:127
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
CxxUtils::tokenize
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
Definition: Control/CxxUtils/Root/StringUtils.cxx:15
xAOD::MuonSimHit_v1::setPdgId
void setPdgId(int id)
Sets the pdgID of the traversing particle.
MuonG4R4::getTransform
Amg::Transform3D getTransform(const G4VTouchable *history, unsigned int level)
Extracts the local -> global transformation from a TouchableHistory at a given level.
Definition: MuonSpectrometer/MuonPhaseII/MuonG4/MuonSensitiveDetectorsR4/MuonSensitiveDetectorsR4/Utils.h:24
TrackHelper.h
xAOD::toStorage
MeasVector< N > toStorage(const AmgVector(N)&amgVec)
Converts the double precision of the AmgVector into the floating point storage precision of the MeasV...
Definition: MeasurementDefs.h:68
Muon::IMuonIdHelperSvc::toStringDetEl
virtual std::string toStringDetEl(const Identifier &id) const =0
print all fields up to detector element to string
MuonSimHitAuxContainer.h
xAOD::MuonSimHit_v1::setLocalPosition
void setLocalPosition(MeasVector< 3 > vec)
Sets the local position of the traversing particle.
Definition: xAODMuonSimHit_V1.cxx:55
MuonGMR4::MuonReadoutElement::globalToLocalTrans
Amg::Transform3D globalToLocalTrans(const ActsGeometryContext &ctx) const
Transformations to translate between local <-> global coordinates.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MuonReadoutElement.cxx:78
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::MuonSimHit_v1::setGenParticleLink
void setGenParticleLink(const HepMcParticleLink &link)
Sets the link to the HepMC particle producing this hit.
Definition: xAODMuonSimHit_V1.cxx:82
THROW_EXCEPTION
#define THROW_EXCEPTION(MSG)
Definition: MMReadoutElement.cxx:48
Muon::IMuonIdHelperSvc::mmIdHelper
virtual const MmIdHelper & mmIdHelper() const =0
access to CscIdHelper
CaloSwCorrections.gap
def gap(flags, cells_name, *args, **kw)
Definition: CaloSwCorrections.py:212
MuonG4R4::MmSensitiveDetector::m_writeHandle
SG::WriteHandle< xAOD::MuonSimHitContainer > m_writeHandle
Definition: MmSensitiveDetector.h:66
xAOD::MuonSimHit_v1::setMass
void setMass(const float m)
set the rest-mass of the traversing particle
Amg::Hep3VectorToEigen
Amg::Vector3D Hep3VectorToEigen(const CLHEP::Hep3Vector &CLHEPvector)
Converts a CLHEP-based CLHEP::Hep3Vector into an Eigen-based Amg::Vector3D.
Definition: CLHEPtoEigenConverter.h:137
TrackHelper
Definition: TrackHelper.h:14
xAOD::MuonSimHit_v1::setKineticEnergy
void setKineticEnergy(const float energy)
Sets the kinetic energy of the traversing particle.
MuonG4R4
Include the common definitions from the MuonReadoutGeometry.
Definition: MuonSpectrometer/MuonPhaseII/MuonG4/MuonSensitiveDetectorsR4/MuonSensitiveDetectorsR4/Utils.h:14
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
MuonGMR4
Definition: ChamberAssembleTool.h:16
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
CxxUtils
Definition: aligned_vector.h:29
MuonGMR4::MmReadoutElement::measurementId
Identifier measurementId(const IdentifierHash &measHash) const override final
Converts the measurement hash back to the full Identifier.
MuonGMR4::MuonReadoutElement::center
Amg::Vector3D center(const ActsGeometryContext &ctx) const
Returns the detector center (Which is the same as the detector center of the first measurement layer)
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
python.SystemOfUnits.micrometer
int micrometer
Definition: SystemOfUnits.py:71
MuonG4R4::MmSensitiveDetector::ProcessHits
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROhist) override final
Definition: MmSensitiveDetector.cxx:56
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
CLHEPtoEigenConverter.h
tolerance
Definition: suep_shower.h:17
Utils.h
xAOD::MuonSimHit_v1::setEnergyDeposit
void setEnergyDeposit(const float deposit)
Sets the energy deposited by the traversing particle inside the gas volume.
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
xAOD::MuonSimHit_v1::setLocalDirection
void setLocalDirection(MeasVector< 3 > vec)
Sets the local direction of the traversing particle.
Definition: xAODMuonSimHit_V1.cxx:61
MuonGMR4::MuonReadoutElement::identify
Identifier identify() const override final
Return the athena identifier.
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
MuonG4R4::MmSensitiveDetector::getReadoutElement
const MuonGMR4::MmReadoutElement * getReadoutElement(const ActsGeometryContext &gctx, const G4TouchableHistory *touchHist) const
Retrieves the matching readout element to a G4 hit.
Definition: MmSensitiveDetector.cxx:146
MmIdHelper
Definition: MmIdHelper.h:54
MuonGMR4::MuonDetectorManager::idHelperSvc
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns a pointer to the central MuonIdHelperSvc.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MuonDetectorManager.cxx:132
CxxUtils::atoi
int atoi(std::string_view str)
Helper functions to unpack numbers decoded in string into integers and doubles The strings are requir...
Definition: Control/CxxUtils/Root/StringUtils.cxx:85
ActsTrk
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Definition: MuonDetectorBuilderTool.cxx:34
MuonG4R4::MmSensitiveDetector::m_trfCacheKey
SG::ReadHandleKey< ActsTrk::DetectorAlignStore > m_trfCacheKey
ReadHandleKey to the DetectorAlignmentStore caching the relevant transformations needed in this event...
Definition: MmSensitiveDetector.h:71
TrackHelper::GenerateParticleLink
HepMcParticleLink GenerateParticleLink()
Generates a creates new HepMcParticleLink object on the stack based on GetUniqueID(),...
Definition: TrackHelper.h:35
MuonG4R4::MmSensitiveDetector::Initialize
void Initialize(G4HCofThisEvent *HCE) override final
member functions
Definition: MmSensitiveDetector.cxx:44
MuonG4R4::MmSensitiveDetector::m_detMgr
const MuonGMR4::MuonDetectorManager * m_detMgr
Pointer to the underlying detector manager.
Definition: MmSensitiveDetector.h:74
MmIdHelper::channelID
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
Definition: MmIdHelper.cxx:736
NSWL1::globalToLocal
Polygon globalToLocal(const Polygon &pol, float z, const Trk::PlaneSurface &surf)
Definition: GeoUtils.cxx:103
xAOD::MuonSimHit_v1::setGlobalTime
void setGlobalTime(const float time)
Sets the time of the traversing particle.
xAOD::MuonSimHit
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition: MuonSimHit.h:12