ATLAS Offline Software
RpcSensitiveDetector.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "RpcSensitiveDetector.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 "GaudiKernel/SystemOfUnits.h"
18 #include "GeoModelHelpers/throwExcept.h"
19 
20 using namespace MuonGMR4;
21 using namespace CxxUtils;
22 using namespace ActsTrk;
23 
24 namespace {
25  constexpr double tolerance = 10. * Gaudi::Units::micrometer;
26 }
27 // construction/destruction
28 namespace MuonG4R4 {
29 
30 RpcSensitiveDetector::RpcSensitiveDetector(const std::string& name,
31  const std::string& output_key,
32  const std::string& trf_storeKey,
33  const MuonGMR4::MuonDetectorManager* detMgr):
34  G4VSensitiveDetector{name},
36  m_writeHandle{output_key},
37  m_trfCacheKey{trf_storeKey},
38  m_detMgr{detMgr} {
39  m_trfCacheKey.initialize().ignore();
40 }
41 
42 void RpcSensitiveDetector::Initialize(G4HCofThisEvent*) {
43  if (m_writeHandle.isValid()) {
44  ATH_MSG_VERBOSE("Simulation hit container "<<m_writeHandle.fullKey()<<" is already written");
45  return;
46  }
47  if (!m_writeHandle.recordNonConst(std::make_unique<xAOD::MuonSimHitContainer>(),
48  std::make_unique<xAOD::MuonSimHitAuxContainer>()).isSuccess()) {
49  THROW_EXCEPTION(" Failed to record "<<m_writeHandle.fullKey());
50  }
51  ATH_MSG_DEBUG("Output container "<<m_writeHandle.fullKey()<<" has been successfully created");
52 }
53 
54 G4bool RpcSensitiveDetector::ProcessHits(G4Step* aStep,G4TouchableHistory*) {
55 
56 
57  G4Track* currentTrack = aStep->GetTrack();
58 
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  const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(currentTrack->GetTouchable());
70  const MuonGMR4::RpcReadoutElement* readOutEle = getReadoutElement(touchHist);
71  if (!readOutEle) {
72  return false;
73  }
74 
75  ActsGeometryContext gctx{};
76 
78  if (!trfStoreHandle.isValid()) {
79  ATH_MSG_FATAL("Failed to retrieve "<<m_trfCacheKey.fullKey()<<".");
80  return false;
81  }
82  gctx.setStore(std::make_unique<DetectorAlignStore>(*trfStoreHandle));
83 
84  const Amg::Transform3D globalToLocal = getTransform(touchHist, 0).inverse();
85  ATH_MSG_VERBOSE(" Track is inside volume "
86  <<touchHist->GetHistory()->GetTopVolume()->GetName()
87  <<" transformation: "<<Amg::toString(globalToLocal));
88  // transform pre and post step positions to local positions
89 
90  const Amg::Vector3D localPos{globalToLocal*Amg::Hep3VectorToEigen(currentTrack->GetPosition())};
91  const Amg::Vector3D localDir{globalToLocal.linear()*Amg::Hep3VectorToEigen(currentTrack->GetMomentumDirection())};
92  ATH_MSG_VERBOSE("Entry / exit point in "<<m_detMgr->idHelperSvc()->toStringDetEl(readOutEle->identify())
93  <<" "<<Amg::toString(localPos, 2)<<" / "<<Amg::toString(localDir, 2));
94 
95 
96  // The middle of the gas gap is at X= 0
97  std::optional<double> travelDist = Amg::intersect<3>(localPos, localDir, Amg::Vector3D::UnitX(), 0.);
98  if (!travelDist) return true;
99  const Amg::Vector3D locGapCross = localPos + (*travelDist) * localDir;
100  ATH_MSG_VERBOSE("Propagation to the gas gap center: "<<Amg::toString(locGapCross, 2));
101  const Amg::Vector3D gapCenterCross = globalToLocal.inverse() * locGapCross;
102 
103  const Identifier etaHitID = getIdentifier(gctx, readOutEle, gapCenterCross, false);
104  if (!etaHitID.is_valid()) {
105  ATH_MSG_VERBOSE("No valid hit found");
106  return true;
107  }
108  const double globalTime = currentTrack->GetGlobalTime() + (*travelDist) / currentTrack->GetVelocity();
109  const Amg::Transform3D gapTrans{readOutEle->globalToLocalTrans(gctx, etaHitID)};
110  const Amg::Vector3D locHitDir = gapTrans.linear() * Amg::Hep3VectorToEigen(currentTrack->GetMomentumDirection());
111  const Amg::Vector3D locHitPos = gapTrans * gapCenterCross;
112 
114  if (std::abs(locHitPos.z()) > tolerance) {
115  ATH_MSG_FATAL("The hit "<<Amg::toString(locHitPos)<<" doest not match "<<m_detMgr->idHelperSvc()->toString(etaHitID));
116  throw std::runtime_error("Picked wrong gas gap");
117  }
118 
119  xAOD::MuonSimHit* hit = new xAOD::MuonSimHit();
120  m_writeHandle->push_back(hit);
121 
122  TrackHelper trHelp(aStep->GetTrack());
123  hit->setIdentifier(etaHitID);
124  hit->setLocalPosition(xAOD::toStorage(locHitPos));
125  hit->setLocalDirection(xAOD::toStorage(locHitDir));
126  hit->setMass(currentTrack->GetDefinition()->GetPDGMass());
127  hit->setGlobalTime(globalTime);
128  hit->setPdgId(currentTrack->GetDefinition()->GetPDGEncoding());
129  hit->setEnergyDeposit(aStep->GetTotalEnergyDeposit());
130  hit->setKineticEnergy(currentTrack->GetKineticEnergy());
132  return true;
133 }
134 
136  const MuonGMR4::RpcReadoutElement* readOutEle,
137  const Amg::Vector3D& hitAtGapPlane, bool phiGap) const {
138  const RpcIdHelper& idHelper{m_detMgr->idHelperSvc()->rpcIdHelper()};
139 
140  const Identifier firstChan = idHelper.channelID(readOutEle->identify(),
141  readOutEle->doubletZ(),
142  readOutEle->doubletPhi(), 1, phiGap, 1);
143 
144  const Amg::Vector3D locHitPos{readOutEle->globalToLocalTrans(gctx, firstChan) *
145  hitAtGapPlane};
146  const double gapHalfWidth = readOutEle->stripEtaLength() / 2;
147  const double gapHalfLength = readOutEle->stripPhiLength()/ 2;
148  ATH_MSG_VERBOSE("Detector element: "<<m_detMgr->idHelperSvc()->toStringDetEl(firstChan)
149  <<" locPos: "<<Amg::toString(locHitPos, 2)
150  <<" gap thickness "<<readOutEle->gasGapPitch()
151  <<" gap width: "<<gapHalfWidth
152  <<" gap length: "<<gapHalfLength);
153  const int doubletPhi = std::abs(locHitPos.y()) > gapHalfWidth ? readOutEle->doubletPhiMax() :
154  readOutEle->doubletPhi();
155  const int gasGap = std::round(std::abs(locHitPos.z()) / readOutEle->gasGapPitch()) + 1;
156 
157  return idHelper.channelID(readOutEle->identify(),
158  readOutEle->doubletZ(),
159  doubletPhi, gasGap, phiGap, 1);
160 }
161 const MuonGMR4::RpcReadoutElement* RpcSensitiveDetector::getReadoutElement(const G4TouchableHistory* touchHist) const {
163  const std::string stationVolume = touchHist->GetVolume(3)->GetName();
164 
165  const std::vector<std::string> volumeTokens = tokenize(stationVolume, "_");
166  ATH_MSG_VERBOSE("Name of the station volume is "<<stationVolume);
167  if (volumeTokens.size() != 7) {
168  THROW_EXCEPTION(" Cannot deduce the station name from "<<stationVolume);
169  }
172  const std::string stName = volumeTokens[0].substr(0,3);
173  const int stationEta = atoi(volumeTokens[2]);
174  const int stationPhi = atoi(volumeTokens[3]);
175  const int doubletR = atoi(volumeTokens[4]);
176  const int doubletPhi = atoi(volumeTokens[5]);
177  const int doubletZ = atoi(volumeTokens[6]);
178  const RpcIdHelper& idHelper{m_detMgr->idHelperSvc()->rpcIdHelper()};
179 
180  const Identifier detElId = idHelper.padID(idHelper.stationNameIndex(stName),
181  stationEta, stationPhi, doubletR, doubletZ, doubletPhi);
182  const RpcReadoutElement* readOutElem = m_detMgr->getRpcReadoutElement(detElId);
183  if (!readOutElem) {
184  THROW_EXCEPTION(" Failed to retrieve a valid detector element from "
185  <<m_detMgr->idHelperSvc()->toStringDetEl(detElId)<<" "<<stationVolume);
186  }
187  return readOutElem;
188 }
189 }
MuonGMR4::RpcReadoutElement::doubletPhiMax
int doubletPhiMax() const
Returns the maximum phi panel.
MuonG4R4::RpcSensitiveDetector::getReadoutElement
const MuonGMR4::RpcReadoutElement * getReadoutElement(const G4TouchableHistory *touchHist) const
Retrieves the matching readout element to a G4 hit.
Definition: RpcSensitiveDetector.cxx:161
MuonGMR4::RpcReadoutElement::stripPhiLength
double stripPhiLength() const
Returns the length of a phi strip.
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
xAOD::MuonSimHit_v1
Definition: MuonSimHit_v1.h:18
dumpTgcDigiDeadChambers.gasGap
list gasGap
Definition: dumpTgcDigiDeadChambers.py:33
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
MuonG4R4::RpcSensitiveDetector::m_writeHandle
SG::WriteHandle< xAOD::MuonSimHitContainer > m_writeHandle
Definition: RpcSensitiveDetector.h:126
MuonGMR4::MuonDetectorManager
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonDetectorManager.h:62
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
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
createCablingJSON.doubletR
int doubletR
Definition: createCablingJSON.py:10
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
MuonG4R4::RpcSensitiveDetector::getIdentifier
Identifier getIdentifier(const ActsGeometryContext &gctx, const MuonGMR4::RpcReadoutElement *readOutEle, const Amg::Vector3D &hitAtGapPlane, bool phiGap) const
Extracts the gasGap Identifier of the hit expressed at the origin of the local gasGap system.
Definition: RpcSensitiveDetector.cxx:135
MuonGMR4::RpcReadoutElement
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/RpcReadoutElement.h:17
RpcIdHelper
Definition: RpcIdHelper.h:51
MuonG4R4::RpcSensitiveDetector::m_trfCacheKey
SG::ReadHandleKey< ActsTrk::DetectorAlignStore > m_trfCacheKey
ReadHandleKey to the DetectorAlignmentStore caching the relevant transformations needed in this event...
Definition: RpcSensitiveDetector.h:131
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
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
Definition: MdtCalibInput.h:20
RpcSensitiveDetector.h
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
MuonGMR4::RpcReadoutElement::doubletPhi
int doubletPhi() const
Returns the doublet Phi field of the MuonReadoutElement identifier.
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
CxxUtils
Definition: aligned_vector.h:29
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
MuonG4R4::RpcSensitiveDetector::m_detMgr
const MuonGMR4::MuonDetectorManager * m_detMgr
Pointer to the underlying detector manager.
Definition: RpcSensitiveDetector.h:134
MuonGMR4::RpcReadoutElement::doubletZ
int doubletZ() const
Returns the doublet Z field of the MuonReadoutElement identifier.
python.SystemOfUnits.micrometer
int micrometer
Definition: SystemOfUnits.py:71
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
MuonG4R4::RpcSensitiveDetector::ProcessHits
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROhist) override final
Definition: RpcSensitiveDetector.cxx:54
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.
MuonG4R4::RpcSensitiveDetector::Initialize
void Initialize(G4HCofThisEvent *HCE) override final
member functions
Definition: RpcSensitiveDetector.cxx:42
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
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
Muon::IMuonIdHelperSvc::toString
virtual std::string toString(const Identifier &id) const =0
print all fields to string
MuonGMR4::MuonDetectorManager::idHelperSvc
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns a pointer to the central MuonIdHelperSvc.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MuonDetectorManager.cxx:140
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
createCablingJSON.doubletPhi
int doubletPhi
Definition: createCablingJSON.py:11
ActsTrk
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Definition: MuonDetectorBuilderTool.cxx:49
TrackHelper::GenerateParticleLink
HepMcParticleLink GenerateParticleLink()
Generates a creates new HepMcParticleLink object on the stack based on GetUniqueID(),...
Definition: TrackHelper.h:35
NSWL1::globalToLocal
Polygon globalToLocal(const Polygon &pol, float z, const Trk::PlaneSurface &surf)
Definition: GeoUtils.cxx:103
MuonGMR4::RpcReadoutElement::stripEtaLength
double stripEtaLength() const
Returns the length of an eta strip.
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
Muon::IMuonIdHelperSvc::rpcIdHelper
virtual const RpcIdHelper & rpcIdHelper() const =0
access to RpcIdHelper
MuonGMR4::RpcReadoutElement::gasGapPitch
double gasGapPitch() const
Returns the thickness of a RPC gasgap.
Identifier
Definition: IdentifierFieldParser.cxx:14