ATLAS Offline Software
MDTSensitiveDetectorCosmics.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
7 #include "MCTruth/TrackHelper.h"
8 #include "G4Geantino.hh"
9 #include "G4ChargedGeantino.hh"
11 
12 #include <string>
13 #include <iostream>
14 #include <limits>
15 
17 
18 namespace {
19  // the tube number of a tube in a tubeLayer in encoded in the GeoSerialIdentifier (modulo maxNTubesPerLayer)
20  constexpr unsigned int maxNTubesPerLayer = MdtIdHelper::maxNTubesPerLayer;
21 }
22 
23 typedef std::istringstream my_isstream;
24 
25 // construction/destruction
26 MDTSensitiveDetectorCosmics::MDTSensitiveDetectorCosmics(const std::string& name, const std::string& hitCollectionName, const unsigned int nTubesMax)
27  : G4VSensitiveDetector( name )
28  , m_momMag(0.)
29  , m_MDTHitColl( hitCollectionName )
30  , m_driftRadius(0.)
31  , m_globalTime(0.)
32  , m_DEFAULT_TUBE_RADIUS( std::numeric_limits<double>::max() )
33 {
35 }
36 
37 // Implemenation of member functions
39 {
40  if (!m_MDTHitColl.isValid()) m_MDTHitColl = std::make_unique<MDTSimHitCollection>();
42  // START OF COSMICS SPECIFIC CODE
43  m_mom = Amg::Vector3D(0.,0.,0.);
44  m_globH = Amg::Vector3D(0.,0.,0.);
45  // END OF COSMICS SPECIFIC CODE
46 }
47 
48 G4bool MDTSensitiveDetectorCosmics::ProcessHits(G4Step* aStep,G4TouchableHistory* /*ROHist*/) {
49 
50  G4Track* currentTrack = aStep->GetTrack();
51 
52  // MDTs sensitive to charged particle only
53  if (currentTrack->GetDefinition()->GetPDGCharge() == 0.0) {
54  if (currentTrack->GetDefinition()!=G4Geantino::GeantinoDefinition()) return true;
55  else if (currentTrack->GetDefinition()==G4ChargedGeantino::ChargedGeantinoDefinition()) return true;
56  }
57 
58  G4VPhysicalVolume* physVolPostStep = aStep->GetPostStepPoint()->GetPhysicalVolume();
59  if (nullptr == physVolPostStep) return true;
60 
61  // hit information to be recorded
62  double globalTime;
63  double driftRadius;
64  Amg::Vector3D localPosition;
65  localPosition.setZero();
66 
67  // get top transformation
68  const G4AffineTransform trans = currentTrack->GetTouchable()->GetHistory()->GetTopTransform();
69 
70  // START OF COSMICS SPECIFIC CODE
71  // global coordinates
72  G4ThreeVector globVrtx = aStep->GetPreStepPoint()->GetPosition();
73 
74  // distance of the hit from (0,0,0) vertex - calculated from the PreStepPoint (approximation)
75  double dist = globVrtx.mag();
76  double lightspeed = 299.792458; /* in vacuo speed of light [mm/ns] */
77  double tOrigin = dist / lightspeed;
78 
79  G4int trackid = aStep->GetTrack()->GetTrackID();
80  m_currVertex = Amg::Hep3VectorToEigen( aStep->GetTrack()->GetVertexPosition() );
81 
82  // for cosmics: only primary muon tracks - track momentum when first entering the spectrometer (one muon per event)
83  if ((m_currVertex != m_vertex) && (trackid == 1)) {
84  // after calculationg the momentum magnidude, normalize it
85  m_mom = Amg::Hep3VectorToEigen( currentTrack->GetMomentum() );
86  m_momMag = m_mom.mag();
87  m_mom.normalize();
88  // the direction of the primary mu is used to calculate the t0, the position ot the t0, m_globH, is ONE for a track
89  Amg::Vector3D globVrtxFix = Amg::Hep3VectorToEigen( globVrtx );
90  double AlphaGlobal = -1*(globVrtxFix[0]*m_mom[0] + globVrtxFix[1]*m_mom[1] + globVrtxFix[2]*m_mom[2])/(m_mom[0]*m_mom[0] + m_mom[1]*m_mom[1] + m_mom[2]*m_mom[2]);
91  m_globH = globVrtxFix + AlphaGlobal*m_mom;
92 // G4cout << "COSMICS MAIN TRACK IN THE MDT!" << G4endl;
93  }
94  double globalDist = sqrt((m_globH[0] - globVrtx[0])*(m_globH[0] - globVrtx[0]) +
95  (m_globH[1] - globVrtx[1])*(m_globH[1] - globVrtx[1]) +
96  (m_globH[2] - globVrtx[2])*(m_globH[2] - globVrtx[2]));
97  double tof = globalDist / lightspeed;
98  // END OF COSMICS SPECIFIC CODE
99 
100  // transform pre and post step positions to local positions
101 
102  Amg::Vector3D localVertex1( Amg::Hep3VectorToEigen( trans.TransformPoint(aStep->GetPreStepPoint()->GetPosition()) ) );
103  Amg::Vector3D localVertex2( Amg::Hep3VectorToEigen( trans.TransformPoint(aStep->GetPostStepPoint()->GetPosition()) ) );
104 
105  // calculate local direction from begin- and end-point of the step
106  Amg::Vector3D localDirection( (localVertex2 - localVertex1) ); // normalized
107  localDirection.z() = 0.; // look in xy-plane
108 
109  // See if particle passed wire by projecting begin- and end-point on the step direction
110  if( (localVertex2.dot(localDirection)) * (localVertex1.dot(localDirection)) < 0 ) { // particle passed wire
111 
112  // compute drift radius ( = impact parameter)
113  double Xpos = localVertex1[0];
114  double Ypos = localVertex1[1];
115  double Xdir = localDirection[0];
116  double Ydir = localDirection[1];
117 
118  double Alpha = -1*(Xpos*Xdir + Ypos*Ydir)/(Xdir*Xdir + Ydir*Ydir); // localPosition*localDirection
119 
120  localPosition = localVertex1 + Alpha*(localVertex2-localVertex1);
121  driftRadius = localPosition.perp();
122  globalTime = aStep->GetPreStepPoint()->GetGlobalTime(); // take pre step time
123 
124  }else{ // particle didn't pass wire, one of the end-points is the shortest distance to the wire
125 
126  // calculate which of the two end-points is closer to the wire
127  double dist1 = localVertex1.perp();
128  double dist2 = localVertex2.perp();
129  if( dist1 < dist2 ){ // first is closer
130  driftRadius = dist1;
131  localPosition = localVertex1;
132  globalTime = aStep->GetPreStepPoint()->GetGlobalTime();
133  }else{ // second is closer
134  driftRadius = dist2;
135  localPosition = localVertex2;
136  globalTime = aStep->GetPostStepPoint()->GetGlobalTime();
137  }
138  }
139  m_vertex = Amg::Hep3VectorToEigen( aStep->GetTrack()->GetVertexPosition() );
140 
141  if( driftRadius < m_driftRadius ){ // check if current step came closer to the wire than the previous ones
143  // if the track m_vertex is far from (0,0,0), takes the tof, otherwise take the "usual" g4 globalTime
144  ((((m_vertex.mag()) < 100) || ((fabs(globalTime - tOrigin)) < 0.1) ) ? (m_globalTime = globalTime) : (m_globalTime = tof));
145  // if m_globalTime != globalTime and m_globalTime != tof in the output, this is due to multiple hits
146  // before founding the good one (small approximation)
147  m_localPosition = localPosition;
148  }
149 
150  // check if particle left tube or stopped in tube
151  G4String namePreStepMat = aStep->GetPreStepPoint()->GetMaterial()->GetName();
152  G4String namePostStepMat = aStep->GetPostStepPoint()->GetMaterial()->GetName();
153  G4String nameSD = aStep->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetSensitiveDetector()->GetName();
154 
155  // see if we were in the sensitive volume and left it, or the particle was killed
156  if( ((nameSD) && (namePreStepMat != namePostStepMat)) || (currentTrack->GetTrackStatus() == fStopAndKill)){
157 
158  // get identifier
159  const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(aStep->GetPreStepPoint()->GetTouchable());
160  int MDTid = GetIdentifier(touchHist);
161 
162  TrackHelper trHelp(aStep->GetTrack());
163 
164  // construct new mdt hit
166  aStep->GetStepLength(),
167  aStep->GetTotalEnergyDeposit(),
168  currentTrack->GetDefinition()->GetPDGEncoding(),
169  aStep->GetPreStepPoint()->GetKineticEnergy());
170 
171  m_driftRadius = m_DEFAULT_TUBE_RADIUS; // reset start value of driftRadius
172  }
173  return true;
174 }
175 
176 int MDTSensitiveDetectorCosmics::GetIdentifier(const G4TouchableHistory* touchHist)
177 {
178  // attributes of the MDT identifier construction
179  std::string stationName;
180  int stationEta=0;
181  int stationPhi=0;
182  int multilayer=0;
183  int tubeLayer=0;
184  int tube=0;
185 
186  bool isAssembly = false;
187  // scan geometry tree to identify the tube
188  for (int i = touchHist->GetHistoryDepth(); i>=0; i--) {
189 
190  std::string::size_type npos;
191  std::string::size_type loc1;
192  std::string::size_type loc2;
193  std::string volName = touchHist->GetVolume(i)->GetName();
194 
195  // check if this station is an assembly
196  if ((npos = volName.find("av_")) != std::string::npos &&
197  (npos = volName.find("impr_")) != std::string::npos) isAssembly = true;
198 
199  // station: name, eta and phi (-> chamber!)
200  if ((npos = volName.find("station")) != std::string::npos && (!isAssembly)) {
201 
202  volName.resize(npos-2);
203  int volCopyNo = touchHist->GetVolume(i)->GetCopyNo();
204  volCopyNo=volCopyNo%1000;
205  stationName = volName;
206  stationEta = volCopyNo/100;
207  stationPhi = abs(volCopyNo%100);
208 
209  }
210  else if ((npos = volName.find("component")) != std::string::npos && (!isAssembly)) { // multilayer
211 
212  int gmID = 0;
213  if ((loc1 = volName.find('[')) != std::string::npos) {
214  if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
215  std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
216  istrvar>>gmID;
217  }
218  }
219  multilayer = gmID;
220 
221  } else if ((npos = volName.find("MDT")) != std::string::npos && isAssembly) {
222 
223  // vol name for Assembly components are
224  // av_WWW_impr_XXX_Muon::BMSxMDTxx_pv_ZZZ_NAME
225  // where WWW is ass. istance nr.
226  // XXX is comp. imprint nr.
227  // BMSxMDTxx is the name of the comp. log.Vol.
228  // x station sub-type; xx technology subtype
229  // ZZZ is the comp. number of order
230  // NAME is the comp. tag (geoIdentifierTag)
231  // for MDTs NAME is ml[1] or ml[2]
232  // copy numbers for Ass.components are =
233  // CopyNoBase(= geoIdentifierTag of the assembly) + geoIdentifierTag of the component
234  // geoIdentifierTag of the component = Job
235  // geoIdentifierTag of the assembly = (sideC*10000 +
236  // mirsign*1000 + abs(zi)*100 + fi+1)*100000;
237  // mirsign*1000 + abs(zi)*100 + fi+1)*100000;
238  //
239  if ((loc1 = volName.find("Muon::")) != std::string::npos) {
240  stationName = volName.substr(loc1+6,3);
241  }
242 
243  int copyNr = touchHist->GetVolume(i)->GetCopyNo();
244  int copyNrBase = int(copyNr/100000);
245  int sideC = int(copyNrBase/10000);
246  int zi = int((copyNrBase%1000)/100);
247  int fi = int(copyNrBase%100);
248  if (sideC == 1) zi = -zi;
249  stationEta = zi;
250  stationPhi = fi;
251 
252  int gmID = 0;
253  if ((loc1 = volName.find('[')) != std::string::npos) {
254  if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
255  std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
256  istrvar>>gmID;
257  }
258  }
259  multilayer = gmID;
260  } else if ((npos = volName.find("Drift")) != std::string::npos) { // layer and tube
261  tubeLayer = touchHist->GetVolume(i)->GetCopyNo()/maxNTubesPerLayer;
262  tube = touchHist->GetVolume(i)->GetCopyNo()%maxNTubesPerLayer;
263  }
264  }
265  //construct the hit identifier
266  return m_muonHelper->BuildMdtHitId(stationName, stationPhi, stationEta, multilayer,tubeLayer, tube);
267 }
MDTSensitiveDetectorCosmics::m_globH
Amg::Vector3D m_globH
Definition: MDTSensitiveDetectorCosmics.h:109
Muon::nsw::STGTPSegments::moduleIDBits::stationPhi
constexpr uint8_t stationPhi
station Phi 1 to 8
Definition: NSWSTGTPDecodeBitmaps.h:158
MDTSensitiveDetectorCosmics::m_muonHelper
const MdtHitIdHelper * m_muonHelper
Definition: MDTSensitiveDetectorCosmics.h:113
max
#define max(a, b)
Definition: cfImp.cxx:41
MDTSensitiveDetectorCosmics::m_momMag
double m_momMag
Definition: MDTSensitiveDetectorCosmics.h:106
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
dumpTgcDigiDeadChambers.stationName
dictionary stationName
Definition: dumpTgcDigiDeadChambers.py:30
MDTSensitiveDetectorCosmics.h
TrackHelper.h
MDTSensitiveDetectorCosmics::m_driftRadius
double m_driftRadius
Definition: MDTSensitiveDetectorCosmics.h:115
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:35
MDTSensitiveDetectorCosmics::Initialize
void Initialize(G4HCofThisEvent *HCE) override final
member functions
Definition: MDTSensitiveDetectorCosmics.cxx:38
MDTSensitiveDetectorCosmics::m_globalTime
double m_globalTime
Definition: MDTSensitiveDetectorCosmics.h:116
MdtHitIdHelper::GetHelper
static const MdtHitIdHelper * GetHelper(unsigned int nTubes=78)
Definition: MdtHitIdHelper.cxx:24
MDTSensitiveDetectorCosmics::m_DEFAULT_TUBE_RADIUS
double m_DEFAULT_TUBE_RADIUS
radius assigned to radius if radius is invalid
Definition: MDTSensitiveDetectorCosmics.h:120
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
MDTSensitiveDetectorCosmics::m_vertex
Amg::Vector3D m_vertex
Definition: MDTSensitiveDetectorCosmics.h:107
MdtIdHelper.h
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
CLHEPtoEigenConverter.h
MDTSensitiveDetectorCosmics::m_currVertex
Amg::Vector3D m_currVertex
Definition: MDTSensitiveDetectorCosmics.h:108
MDTSensitiveDetectorCosmics::m_MDTHitColl
SG::WriteHandle< MDTSimHitCollection > m_MDTHitColl
member data
Definition: MDTSensitiveDetectorCosmics.h:112
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
MDTSensitiveDetectorCosmics::MDTSensitiveDetectorCosmics
MDTSensitiveDetectorCosmics(const std::string &name, const std::string &hitCollectionName, const unsigned int nTubesMax)
construction/destruction
Definition: MDTSensitiveDetectorCosmics.cxx:26
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
MDTSensitiveDetectorCosmics::m_mom
Amg::Vector3D m_mom
Definition: MDTSensitiveDetectorCosmics.h:105
MDTSensitiveDetectorCosmics::GetIdentifier
int GetIdentifier(const G4TouchableHistory *touchHist)
Definition: MDTSensitiveDetectorCosmics.cxx:176
MdtHitIdHelper.h
RPDUtils::sideC
unsigned constexpr int sideC
Definition: RPDUtils.h:15
checkFileSG.fi
fi
Definition: checkFileSG.py:65
my_isstream
std::istringstream my_isstream
Definition: MDTSensitiveDetectorCosmics.cxx:23
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
MDTSensitiveDetectorCosmics::m_localPosition
Amg::Vector3D m_localPosition
Definition: MDTSensitiveDetectorCosmics.h:117
Trk::loc1
@ loc1
Definition: ParamDefs.h:34
MDTSensitiveDetectorCosmics::ProcessHits
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROhist) override final
Definition: MDTSensitiveDetectorCosmics.cxx:48
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