ATLAS Offline Software
MDTSensitiveDetector.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "MDTSensitiveDetector.h"
7 #include "MCTruth/TrackHelper.h"
8 #include "G4Geantino.hh"
9 #include "G4ChargedGeantino.hh"
11 #include <string>
12 #include <limits>
13 
15 
16 namespace {
17  // the tube number of a tube in a tubeLayer in encoded in the GeoSerialIdentifier (modulo maxNTubesPerLayer)
18  constexpr unsigned int maxNTubesPerLayer = MdtIdHelper::maxNTubesPerLayer;
19 }
20 
21 // construction/destruction
22 MDTSensitiveDetector::MDTSensitiveDetector(const std::string& name, const std::string& hitCollectionName, const unsigned int nTubesMax)
23  : G4VSensitiveDetector( name )
24  , m_MDTHitColl( hitCollectionName )
25  , m_driftRadius(0.)
26  , m_globalTime(0.)
27  , m_DEFAULT_TUBE_RADIUS( std::numeric_limits<double>::max() )
28 {
30 }
31 
32 // Implemenation of memebr functions
33 void MDTSensitiveDetector::Initialize(G4HCofThisEvent*)
34 {
35  if (!m_MDTHitColl.isValid()) m_MDTHitColl = std::make_unique<MDTSimHitCollection>();
37 }
38 
39 G4bool MDTSensitiveDetector::ProcessHits(G4Step* aStep,G4TouchableHistory* /*ROHist*/) {
40  G4Track* currentTrack = aStep->GetTrack();
41 
42  // MDTs sensitive to charged particle only
43  if (currentTrack->GetDefinition()->GetPDGCharge() == 0.0) {
44  if (currentTrack->GetDefinition()!=G4Geantino::GeantinoDefinition()) return true;
45  else if (currentTrack->GetDefinition()==G4ChargedGeantino::ChargedGeantinoDefinition()) return true;
46  }
47 
48  G4VPhysicalVolume* physVolPostStep = aStep->GetPostStepPoint()->GetPhysicalVolume();
49  if (nullptr == physVolPostStep) return true;
50 
51  // hit information to be recorded
52  double globalTime;
53  double driftRadius;
54  Amg::Vector3D localPosition;
55  localPosition.setZero();
56 
57  // get top transformation
58  const G4AffineTransform trans = currentTrack->GetTouchable()->GetHistory()->GetTopTransform();
59 
60  // transform pre and post step positions to local positions
61 
62  Amg::Vector3D localVertex1( Amg::Hep3VectorToEigen( trans.TransformPoint(aStep->GetPreStepPoint()->GetPosition()) ) );
63  Amg::Vector3D localVertex2( Amg::Hep3VectorToEigen( trans.TransformPoint(aStep->GetPostStepPoint()->GetPosition()) ) );
64 
65  // calculate local direction from begin- and end-point of the step
66  Amg::Vector3D localDirection( (localVertex2 - localVertex1) ); // normalized
67  localDirection.z() = 0.; // look in xy-plane
68 
69  // See if particle passed wire by projecting begin- and end-point on the step direction
70  if( (localVertex2.dot(localDirection)) * (localVertex1.dot(localDirection)) < 0 ) { // particle passed wire
71 
72  // compute drift radius ( = impact parameter)
73  double Xpos = localVertex1[0];
74  double Ypos = localVertex1[1];
75  double Xdir = localDirection[0];
76  double Ydir = localDirection[1];
77 
78  double Alpha = -1*(Xpos*Xdir + Ypos*Ydir)/(Xdir*Xdir + Ydir*Ydir); // localPosition*localDirection
79 
80  localPosition = localVertex1 + Alpha*(localVertex2-localVertex1);
81  driftRadius = localPosition.perp();
82  globalTime = aStep->GetPreStepPoint()->GetGlobalTime(); // take pre step time
83 
84  }else{ // particle didn't pass wire, one of the end-points is the shortest distance to the wire
85 
86  // calculate which of the two end-points is closer to the wire
87  double dist1 = localVertex1.perp();
88  double dist2 = localVertex2.perp();
89  if( dist1 < dist2 ){ // first is closer
90  driftRadius = dist1;
91  localPosition = localVertex1;
92  globalTime = aStep->GetPreStepPoint()->GetGlobalTime();
93  }else{ // second is closer
94  driftRadius = dist2;
95  localPosition = localVertex2;
96  globalTime = aStep->GetPostStepPoint()->GetGlobalTime();
97  }
98  }
99 
100  if( driftRadius < m_driftRadius ){ // check if current step came closer to the wire than the previous ones
102  m_globalTime = globalTime;
103  m_localPosition = localPosition;
104  }
105 
106  // check if particle left tube or stopped in tube
107  G4String namePreStepMat = aStep->GetPreStepPoint()->GetMaterial()->GetName();
108  G4String namePostStepMat = aStep->GetPostStepPoint()->GetMaterial()->GetName();
109  G4String nameSD = aStep->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetSensitiveDetector()->GetName();
110  // G4int trackid = aStep->GetTrack()->GetTrackID();
111  // see if we were in the sensitive volume and left it, or the particle was killed
112  if( ((nameSD) && (namePreStepMat != namePostStepMat)) || (currentTrack->GetTrackStatus() == fStopAndKill)){
113 
114  // get identifier
115  const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(aStep->GetPreStepPoint()->GetTouchable());
116  int MDTid = GetIdentifier(touchHist);
117 
118  TrackHelper trHelp(aStep->GetTrack());
119 
120  // construct new mdt hit
122  aStep->GetStepLength(),
123  aStep->GetTotalEnergyDeposit(),
124  currentTrack->GetDefinition()->GetPDGEncoding(),
125  aStep->GetPreStepPoint()->GetKineticEnergy());
126 
127  m_driftRadius = m_DEFAULT_TUBE_RADIUS; // reset start value of driftRadius
128  }
129  return true;
130 }
131 
132 int MDTSensitiveDetector::GetIdentifier(const G4TouchableHistory* touchHist)
133 {
134  // attributes of the MDT identifier construction
135  std::string stationName;
136  int stationEta=1;
137  int stationPhi=1;
138  int multilayer=1;
139  int tubeLayer=1;
140  int tube=1;
141 
142  bool isAssembly = false;
143  // scan geometry tree to identify the tube
144  for (int i = touchHist->GetHistoryDepth(); i>=0; i--) {
145 
146  std::string::size_type npos;
147  std::string::size_type loc1;
148  std::string::size_type loc2;
149  std::string volName = touchHist->GetVolume(i)->GetName();
150 
151  // check if this station is an assembly
152  if ((npos = volName.find("av_")) != std::string::npos &&
153  (npos = volName.find("impr_")) != std::string::npos) isAssembly = true;
154 
155  // station: name, eta and phi (-> chamber!)
156  if ((npos = volName.find("station")) != std::string::npos && (!isAssembly)) {
157 
158  volName.resize(npos-2);
159  int volCopyNo = touchHist->GetVolume(i)->GetCopyNo();
160  volCopyNo=volCopyNo%1000;
161  stationName = volName;
162  stationEta = volCopyNo/100;
163  stationPhi = abs(volCopyNo%100);
164 
165  }
166  else if ((npos = volName.find("component")) != std::string::npos && (!isAssembly)) { // multilayer
167 
168  int gmID = 0;
169  if ((loc1 = volName.find('[')) != std::string::npos) {
170  if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
171  std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
172  istrvar>>gmID;
173  }
174  }
175  multilayer = gmID;
176 
177  } else if ((npos = volName.find("MDT")) != std::string::npos && isAssembly) {
178 
179  // vol name for Assembly components are
180  // av_WWW_impr_XXX_Muon::BMSxMDTxx_pv_ZZZ_NAME
181  // where WWW is ass. istance nr.
182  // XXX is comp. imprint nr.
183  // BMSxMDTxx is the name of the comp. log.Vol.
184  // x station sub-type; xx technology subtype
185  // ZZZ is the comp. number of order
186  // NAME is the comp. tag (geoIdentifierTag)
187  // for MDTs NAME is ml[1] or ml[2]
188  // copy numbers for Ass.components are =
189  // CopyNoBase(= geoIdentifierTag of the assembly) + geoIdentifierTag of the component
190  // geoIdentifierTag of the component = Job
191  // geoIdentifierTag of the assembly = (sideC*10000 +
192  // mirsign*1000 + abs(zi)*100 + fi+1)*100000;
193  // mirsign*1000 + abs(zi)*100 + fi+1)*100000;
194  //
195  if ((loc1 = volName.find("Muon::")) != std::string::npos) {
196  stationName = volName.substr(loc1+6,3);
197  }
198 
199  int copyNr = touchHist->GetVolume(i)->GetCopyNo();
200  int copyNrBase = int(copyNr/100000);
201  int sideC = int(copyNrBase/10000);
202  int zi = int((copyNrBase%1000)/100);
203  int fi = int(copyNrBase%100);
204  if (sideC == 1) zi = -zi;
205  stationEta = zi;
206  stationPhi = fi;
207 
208  int gmID = 0;
209  if ((loc1 = volName.find('[')) != std::string::npos) {
210  if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
211  std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
212  istrvar>>gmID;
213  }
214  }
215  multilayer = gmID;
216  } else if ((npos = volName.find("Drift")) != std::string::npos) { // layer and tube
217  tubeLayer = touchHist->GetVolume(i)->GetCopyNo()/maxNTubesPerLayer;
218  tube = touchHist->GetVolume(i)->GetCopyNo()%maxNTubesPerLayer;
219  }
220  }
221  //construct the hit identifier
222  return m_muonHelper->BuildMdtHitId(stationName, stationPhi, stationEta, multilayer,tubeLayer, tube);
223 }
Muon::nsw::STGTPSegments::moduleIDBits::stationPhi
constexpr uint8_t stationPhi
station Phi 1 to 8
Definition: NSWSTGTPDecodeBitmaps.h:158
max
#define max(a, b)
Definition: cfImp.cxx:41
MDTSensitiveDetector::ProcessHits
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROhist) override final
Definition: MDTSensitiveDetector.cxx:39
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
dumpTgcDigiDeadChambers.stationName
dictionary stationName
Definition: dumpTgcDigiDeadChambers.py:30
MDTSensitiveDetector::m_muonHelper
const MdtHitIdHelper * m_muonHelper
Definition: MDTSensitiveDetector.h:103
TrackHelper.h
MDTSensitiveDetector::m_DEFAULT_TUBE_RADIUS
double m_DEFAULT_TUBE_RADIUS
radius assigned to radius if radius is invalid
Definition: MDTSensitiveDetector.h:110
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:35
MdtHitIdHelper::GetHelper
static const MdtHitIdHelper * GetHelper(unsigned int nTubes=78)
Definition: MdtHitIdHelper.cxx:24
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
lumiFormat.i
int i
Definition: lumiFormat.py:85
Trk::driftRadius
@ driftRadius
trt, straws
Definition: ParamDefs.h:53
MDTSensitiveDetector::Initialize
void Initialize(G4HCofThisEvent *HCE) override final
member functions
Definition: MDTSensitiveDetector.cxx:33
MDTSensitiveDetector::m_localPosition
Amg::Vector3D m_localPosition
Definition: MDTSensitiveDetector.h:107
MdtIdHelper.h
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
CLHEPtoEigenConverter.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
MDTSensitiveDetector::m_MDTHitColl
SG::WriteHandle< MDTSimHitCollection > m_MDTHitColl
member data
Definition: MDTSensitiveDetector.h:102
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
MDTSensitiveDetector::MDTSensitiveDetector
MDTSensitiveDetector(const std::string &name, const std::string &hitCollectionName, const unsigned int nTubesMax)
construction/destruction
Definition: MDTSensitiveDetector.cxx:22
MdtHitIdHelper.h
RPDUtils::sideC
unsigned constexpr int sideC
Definition: RPDUtils.h:15
checkFileSG.fi
fi
Definition: checkFileSG.py:65
MDTSensitiveDetector.h
MDTSensitiveDetector::GetIdentifier
int GetIdentifier(const G4TouchableHistory *touchHist)
Definition: MDTSensitiveDetector.cxx:132
TrackHelper::GenerateParticleLink
HepMcParticleLink GenerateParticleLink()
Generates a creates new HepMcParticleLink object on the stack based on GetUniqueID(),...
Definition: TrackHelper.h:35
Muon::nsw::STGTPSegments::moduleIDBits::stationEta
constexpr uint8_t stationEta
1 to 3
Definition: NSWSTGTPDecodeBitmaps.h:156
MdtIdHelper::maxNTubesPerLayer
static constexpr int maxNTubesPerLayer
The maxNTubesPerLayer represents the absolute maximum of tubes which are built into a single multilay...
Definition: MdtIdHelper.h:68
Trk::loc1
@ loc1
Definition: ParamDefs.h:34
calibdata.tube
tube
Definition: calibdata.py:31
MdtHitIdHelper::BuildMdtHitId
int BuildMdtHitId(const std::string &, const int, const int, const int, const int, const int) const
Definition: MdtHitIdHelper.cxx:95
MDTSensitiveDetector::m_driftRadius
double m_driftRadius
Definition: MDTSensitiveDetector.h:105
MDTSensitiveDetector::m_globalTime
double m_globalTime
Definition: MDTSensitiveDetector.h:106