ATLAS Offline Software
MdtSensitiveDetector.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 #include "MdtSensitiveDetector.h"
7 
8 
9 #include <MCTruth/TrackHelper.h>
10 #include <G4Geantino.hh>
11 #include <G4ChargedGeantino.hh>
12 
13 #include <limits>
14 #include <iostream>
16 #include <GeoModelHelpers/throwExcept.h>
18 #include <GaudiKernel/SystemOfUnits.h>
19 #include <StoreGate/ReadHandle.h>
20 
21 using namespace MuonGMR4;
22 using namespace CxxUtils;
23 using namespace ActsTrk;
24 namespace MuonG4R4{
25 
26 MdtSensitiveDetector::MdtSensitiveDetector(const std::string& name,
27  const std::string& output_key,
28  const std::string& trfStore_key,
29  const MuonGMR4::MuonDetectorManager* detMgr):
30  G4VSensitiveDetector{name},
32  m_writeHandle{output_key},
33  m_trfCacheKey{trfStore_key},
34  m_detMgr{detMgr} {
35  m_trfCacheKey.initialize().ignore();
36 }
37 // Implemenation of memebr functions
38 void MdtSensitiveDetector::Initialize(G4HCofThisEvent*) {
39  if (m_writeHandle.isValid()) {
40  ATH_MSG_VERBOSE("Simulation hit container "<<m_writeHandle.fullKey()<<" is already written");
41  return;
42  }
43  if (!m_writeHandle.recordNonConst(std::make_unique<xAOD::MuonSimHitContainer>(),
44  std::make_unique<xAOD::MuonSimHitAuxContainer>()).isSuccess()) {
45  THROW_EXCEPTION(" Failed to record "<<m_writeHandle.fullKey());
46  }
47  ATH_MSG_DEBUG("Output container "<<m_writeHandle.fullKey()<<" has been successfully created");
48 }
49 
50 const MuonGMR4::MdtReadoutElement* MdtSensitiveDetector::getReadoutElement(const G4TouchableHistory* touchHist) const {
52  const std::string stationVolume = touchHist->GetVolume(2)->GetName();
53  using namespace MuonGMR4;
54  const std::vector<std::string> volumeTokens = tokenize(stationVolume, "_");
55  ATH_MSG_VERBOSE("Name of the station volume is "<<stationVolume);
56  if (volumeTokens.size() != 5) {
57  THROW_EXCEPTION(" Cannot deduce the station name from "<<stationVolume);
58  }
60  const std::string stName = volumeTokens[0].substr(0,3);
61  const int stationEta = atoi(volumeTokens[2]);
62  const int stationPhi = atoi(volumeTokens[3]);
63  const int multiLayer = atoi(volumeTokens[4]);
64  const MdtIdHelper& idHelper{m_detMgr->idHelperSvc()->mdtIdHelper()};
66  const Identifier detElId = idHelper.multilayerID(idHelper.elementID(stName,stationEta, stationPhi), multiLayer);
68  const MdtReadoutElement* readOutEle = m_detMgr->getMdtReadoutElement(detElId);
69  if (!readOutEle) {
70  THROW_EXCEPTION(" Failed to retrieve a valid detector element from "
71  <<m_detMgr->idHelperSvc()->toStringDetEl(detElId)<<" "<<stationVolume);
72  }
73  return readOutEle;
74 }
75 
76 G4bool MdtSensitiveDetector::ProcessHits(G4Step* aStep,G4TouchableHistory* /*ROHist*/) {
77  G4Track* currentTrack = aStep->GetTrack();
78 
79  // MDTs sensitive to charged particle only
80  if (currentTrack->GetDefinition()->GetPDGCharge() == 0.0) {
81  if (currentTrack->GetDefinition()!= G4Geantino::GeantinoDefinition()) return true;
82  else if (currentTrack->GetDefinition() != G4ChargedGeantino::ChargedGeantinoDefinition()) return true;
83  }
84 
85 
87  constexpr double velCutOff = 10.*Gaudi::Units::micrometer / Gaudi::Units::second;
88  if (currentTrack->GetVelocity() < velCutOff) return true;
89 
90  const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(currentTrack->GetTouchable());
91  const MdtReadoutElement* reEle{getReadoutElement(touchHist)};
92 
93  ActsGeometryContext gctx{};
94 
96  if (!trfStoreHandle.isValid()) {
97  ATH_MSG_FATAL("Failed to retrieve "<<m_trfCacheKey.fullKey()<<".");
98  return false;
99  }
100  gctx.setStore(std::make_unique<DetectorAlignStore>(*trfStoreHandle));
101 
102  const Identifier HitID = getIdentifier(gctx, reEle, touchHist);
103  if (!HitID.is_valid()) {
104  ATH_MSG_VERBOSE("No valid hit found");
105  return true;
106  }
107 
108  const Amg::Transform3D globalToLocal{reEle->globalToLocalTrans(gctx, reEle->measurementHash(HitID))};
109 
110  // transform pre and post step positions to local positions
111  const Amg::Vector3D trackPosition{Amg::Hep3VectorToEigen(currentTrack->GetPosition())};
112  const Amg::Vector3D trackDirection{Amg::Hep3VectorToEigen(currentTrack->GetMomentumDirection())};
113 
114  const Amg::Vector3D trackLocPos{globalToLocal * trackPosition};
115  const Amg::Vector3D trackLocDir{globalToLocal.linear()* trackDirection};
116 
118  const double lambda = Amg::intersect<3>(Amg::Vector3D::Zero(), Amg::Vector3D::UnitZ(),
119  trackLocPos, trackLocDir).value_or(0);
120 
121  const Amg::Vector3D driftHit{trackLocPos + lambda * trackLocDir};
122 
123  const double globalTime{currentTrack->GetGlobalTime() + lambda / currentTrack->GetVelocity()};
124 
125  TrackHelper trHelp{currentTrack};
126 
127  ATH_MSG_VERBOSE(" Dumping of hit "<<m_detMgr->idHelperSvc()->toString(HitID)
128  <<", barcode: "<<trHelp.GenerateParticleLink().barcode()
129  <<", "<<(*currentTrack)
130  <<", driftCircle: "<<Amg::toString(driftHit, 2)
131  <<", direction "<<Amg::toString(trackLocDir, 2)
132  <<" to SimHit container ahead. ");
133 
134  xAOD::MuonSimHit* hit = new xAOD::MuonSimHit();
135  m_writeHandle->push_back(hit);
136  hit->setIdentifier(HitID);
137  hit->setLocalPosition(xAOD::toStorage(driftHit));
138  hit->setLocalDirection(xAOD::toStorage(trackLocDir));
139  hit->setMass(currentTrack->GetDefinition()->GetPDGMass());
140  hit->setGlobalTime(globalTime);
141  hit->setPdgId(currentTrack->GetDefinition()->GetPDGEncoding());
142  hit->setEnergyDeposit(aStep->GetTotalEnergyDeposit());
143  hit->setKineticEnergy(currentTrack->GetKineticEnergy());
144  hit->setGenParticleLink(trHelp.GenerateParticleLink());
145 
146  return true;
147 }
149  const MuonGMR4::MdtReadoutElement* readOutEle,
150  const G4TouchableHistory* touchHist) const {
151  const Amg::Transform3D localToGlobal{getTransform(touchHist, 0)};
154  Amg::Vector3D refTubePos = (readOutEle->globalToLocalTrans(gctx, readOutEle->measurementHash(1,1)) * localToGlobal).translation();
155  ATH_MSG_VERBOSE("Position of the tube wire w.r.t. the first tube in the multi layer "<<Amg::toString(refTubePos, 2));
157  static const double layerPitch = 1./ std::sin(60*Gaudi::Units::deg);
158  const int layer = std::round(refTubePos.x() * layerPitch / readOutEle->tubePitch()) +1;
159  if (layer <= 0) {
160  THROW_EXCEPTION("Tube hit in nirvana -- It seems that the tube position "
161  <<Amg::toString(refTubePos, 2)<<", perp: "<<refTubePos.perp()
162  <<" is outside of the volume envelope "
163  <<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify())<<". ");
164  }
166  refTubePos = (readOutEle->globalToLocalTrans(gctx, readOutEle->measurementHash(layer,1)) * localToGlobal).translation();
167  const double tubePitches = refTubePos.y() / readOutEle->tubePitch();
168  unsigned int tube = std::round(tubePitches) + 1;
169  tube = std::max(1u, std::min(readOutEle->numTubesInLay(), tube));
172  const Amg::Transform3D closureCheck{readOutEle->globalToLocalTrans(gctx,
173  readOutEle->measurementHash(layer, tube))*localToGlobal};
174  if (!Amg::isIdentity(closureCheck)) {
175  ATH_MSG_WARNING("Correction needed "<<layer<<","<<tube<<" "<<Amg::toString(closureCheck));
176  if (closureCheck.translation().y() > 0) ++tube;
177  else --tube;
178  }
179 
180  const IdentifierHash tubeHash = readOutEle->measurementHash(layer, tube);
181  const Identifier tubeId = readOutEle->measurementId(tubeHash);
182  {
183  const Amg::Transform3D closureCheck{readOutEle->globalToLocalTrans(gctx, tubeHash)*localToGlobal};
184  if (!Amg::isIdentity(closureCheck)) {
185  THROW_EXCEPTION("Tube hit in Nirvana -- It seems that the tube position "
186  <<Amg::toString(refTubePos, 2)<<", perp: "<<refTubePos.perp()
187  <<" is outside of the volume envelope "
188  <<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify())<<". "
189  <<"Layer: "<<layer<<", tube: "<<tube<<" "
190  <<Amg::toString(closureCheck)
191  <<"tube volume : "<<touchHist->GetVolume(0)->GetName()
192  <<" mdt chamber: "<<touchHist->GetVolume(2)->GetName());
193  }
194  }
195  ATH_MSG_VERBOSE("Tube & layer number candidate "<<tube<<", "<<layer<<" back and forth transformation "
196  <<Amg::toString(closureCheck));
197  return tubeId;
198 }
199 
200 }
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
xAOD::MuonSimHit_v1
Definition: MuonSimHit_v1.h:18
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
max
#define max(a, b)
Definition: cfImp.cxx:41
MdtSensitiveDetector.h
MuonGMR4::MdtReadoutElement::numTubesInLay
unsigned int numTubesInLay() const
Returns the number of tubes per layer.
MuonGMR4::MuonDetectorManager
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonDetectorManager.h:61
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
MuonGMR4::MdtReadoutElement::measurementHash
static IdentifierHash measurementHash(unsigned int layerNumber, unsigned int tubeNumber)
Transform the layer and tube number to the measurementHash.
TrackHelper.h
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
deg
#define deg
Definition: SbPolyhedron.cxx:17
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
MuonG4R4::MdtSensitiveDetector::m_detMgr
const MuonGMR4::MuonDetectorManager * m_detMgr
Pointer to the underlying detector manager.
Definition: MdtSensitiveDetector.h:124
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
MuonG4R4::MdtSensitiveDetector::Initialize
void Initialize(G4HCofThisEvent *HCE) override final
member functions
Definition: MdtSensitiveDetector.cxx:38
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
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:83
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
MuonGMR4::MdtReadoutElement::measurementId
Identifier measurementId(const IdentifierHash &measHash) const override final
Converts the measurement hash back to the full Identifier.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtReadoutElement.cxx:45
MuonG4R4::MdtSensitiveDetector::getReadoutElement
const MuonGMR4::MdtReadoutElement * getReadoutElement(const G4TouchableHistory *touchHist) const
Retrieves the matching readout element to a G4 hit.
Definition: MdtSensitiveDetector.cxx:50
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
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
MuonG4R4::MdtSensitiveDetector::getIdentifier
Identifier getIdentifier(const ActsGeometryContext &gctx, const MuonGMR4::MdtReadoutElement *reElement, const G4TouchableHistory *touchHist) const
Retrieves from the Readoutelement & the touchable history the Identifier.
Definition: MdtSensitiveDetector.cxx:148
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
CxxUtils
Definition: aligned_vector.h:29
MdtIdHelper
Definition: MdtIdHelper.h:61
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
Amg::isIdentity
bool isIdentity(const Amg::Transform3D &trans)
Checks whether the transformation is the Identity transformation.
Definition: GeoPrimitivesHelpers.h:348
python.SystemOfUnits.micrometer
int micrometer
Definition: SystemOfUnits.py:71
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
min
#define min(a, b)
Definition: cfImp.cxx:40
CLHEPtoEigenConverter.h
Utils.h
MuonG4R4::MdtSensitiveDetector::ProcessHits
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROhist) override final
Definition: MdtSensitiveDetector.cxx:76
xAOD::MuonSimHit_v1::setEnergyDeposit
void setEnergyDeposit(const float deposit)
Sets the energy deposited by the traversing particle inside the gas volume.
MuonGMR4::MdtReadoutElement
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtReadoutElement.h:19
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
Muon::IMuonIdHelperSvc::mdtIdHelper
virtual const MdtIdHelper & mdtIdHelper() const =0
access to MdtIdHelper
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.
MuonGMR4::MdtReadoutElement::tubePitch
double tubePitch() const
Returns the pitch between 2 tubes in a layer.
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
Muon::IMuonIdHelperSvc::toString
virtual std::string toString(const Identifier &id) const =0
print all fields to string
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
MuonGMR4::MuonDetectorManager::idHelperSvc
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns a pointer to the central MuonIdHelperSvc.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MuonDetectorManager.cxx:132
MdtIdHelper::multilayerID
Identifier multilayerID(const Identifier &channeldID) const
Definition: MdtIdHelper.cxx:332
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
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
ReadHandle.h
Handle class for reading from StoreGate.
HitID
int HitID
Definition: GenericMuonSimHit.h:13
MuonG4R4::MdtSensitiveDetector::m_trfCacheKey
SG::ReadHandleKey< ActsTrk::DetectorAlignStore > m_trfCacheKey
ReadHandleKey to the DetectorAlignmentStore caching the relevant transformations needed in this event...
Definition: MdtSensitiveDetector.h:122
sTgcDigitEffiDump.multiLayer
int multiLayer
Definition: sTgcDigitEffiDump.py:36
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.
calibdata.tube
tube
Definition: calibdata.py:31
xAOD::MuonSimHit
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition: MuonSimHit.h:12
MuonG4R4::MdtSensitiveDetector::m_writeHandle
SG::WriteHandle< xAOD::MuonSimHitContainer > m_writeHandle
Definition: MdtSensitiveDetector.h:117
generate::Zero
void Zero(TH1D *hin)
Definition: generate.cxx:32