ATLAS Offline Software
Loading...
Searching...
No Matches
RPCSensitiveDetector.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 "G4ThreeVector.hh"
7#include "G4Trd.hh"
9#include <string>
10#include "G4Exception.hh"
11#include "G4Geantino.hh"
12#include "G4ChargedGeantino.hh"
13
14//#include "SimHelpers/DetectorGeometryHelper.h"
16#include "MCTruth/TrackHelper.h"
17#include <sstream>
18
19
22#include "GaudiKernel/SystemOfUnits.h"
23
24// construction/destruction
25RPCSensitiveDetector::RPCSensitiveDetector(const std::string& name, const std::string& hitCollectionName, unsigned int nGasGaps)
26 : G4VSensitiveDetector( name )
27 , m_hitCollectionName( hitCollectionName )
28{
30}
31
33{
34 m_myRPCHitColl = nullptr;
35 if (auto* eventInfo = AtlasG4EventUserInfo::GetEventUserInfo()) {
36 m_myRPCHitColl = eventInfo->GetHitCollectionMap()->Find<RPCSimHitCollection>(m_hitCollectionName);
37 m_g4UserEventInfo = eventInfo;
38 }
39 //FIXME probably only need to call this bit at start of the event
40 //loop rather than the start of each G4Event.
41 if (verboseLevel>5) G4cout << "Initializing SD" << G4endl;
42
43}
44
45G4bool RPCSensitiveDetector::ProcessHits(G4Step* aStep,G4TouchableHistory*) {
46
47 if (!m_myRPCHitColl) {
48 G4Exception("RPCSensitiveDetector::ProcessHits", "RPCHitCollectionMissing", FatalException,
49 "Hit collection not initialized; did SetupEvent run?");
50 return false;
51 }
52
53 G4Track* track = aStep->GetTrack();
54
56 if (track->GetDefinition()->GetPDGCharge() == 0.0) {
57 if (track->GetDefinition()!=G4Geantino::GeantinoDefinition()) {
58 return true;
59 }
60 }
61
62 const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(aStep->GetPreStepPoint()->GetTouchable());
63 G4ThreeVector position = aStep->GetPreStepPoint()->GetPosition();
64 G4ThreeVector postPosition = aStep->GetPostStepPoint()->GetPosition();
65 const G4AffineTransform trans = track->GetTouchable()->GetHistory()->GetTopTransform(); // from global to local
66
67 // necessary to assign correct identifiers
68 int rpcIsRotated = 0;
69 // int layer = 0;
70
71 std::string tech;
72 // fields for the RPC identifier construction
73 std::string stationName;
74 int stationEta= 0;
75 int stationPhi= 0;
76 int doubletR= 0;
77 int doubletPhi= 0;
78 int gasGap= 0;
79 int station_rotated=0; // tells us if the station was rotated before being positioned.
80 // if =1 we have to correct some IDs
81 int zNeg_original=0; // tells if the station at z<0 was obtained duplicating a station at z>0
82
83 // RPC hit information
84 double globalTime = aStep->GetPreStepPoint()->GetGlobalTime();
85 Amg::Vector3D localPosition = Amg::Hep3VectorToEigen( trans.TransformPoint(position) );
86 Amg::Vector3D localPostPosition = Amg::Hep3VectorToEigen( trans.TransformPoint(postPosition) );
87 {
88 const Amg::Vector3D stepVector = localPostPosition - localPosition;
90 if (stepVector.mag()>std::numeric_limits<float>::epsilon() &&
91 std::abs(std::abs(Amg::angle(stepVector, Amg::Vector3D::UnitX()))
92 - 90.*Gaudi::Units::deg) < 0.0001* Gaudi::Units::deg) {
93 return true;
94 }
95 }
96 int mydbZ=0;
97 int mydbPMod=0;
98 int mydbP=0;
99 bool isAssembly = false;
100 // scan geometry tree to identify the hit channel
101 for (int i=touchHist->GetHistoryDepth();i>=0;i--) {
102
103 std::string::size_type npos;
104 std::string volName = touchHist->GetVolume(i)->GetName();
105 std::string num=volName.substr(3,2);
106 if(num[0]==' ') num[0]=0;
107
108 // check if this station is an assembly
109 if ((npos = volName.find("av_")) != std::string::npos &&
110 (npos = volName.find("impr_")) != std::string::npos) isAssembly = true;
111
112 // stationName, stationEta, stationPhi
113 if ((npos = volName.find("station")) != std::string::npos && (!isAssembly)) {
114
115 stationName = volName.substr(0,npos-1);
116
117 int volCopyNo = touchHist->GetVolume(i)->GetCopyNo();
118
119 if(abs(volCopyNo/1000)==1){
120 zNeg_original=1;
121 volCopyNo=volCopyNo%1000;
122 }
123
124 stationEta = volCopyNo/100;
125 stationPhi = abs(volCopyNo%100);
126
127 if(stationEta<0&&!zNeg_original) station_rotated=1;
128
129 // stationName, stationEta, stationPhi
130 } else if ((npos = volName.find("RPC")) != std::string::npos && isAssembly) {
131 // vol name for Assembly components are
132 // av_WWW_impr_XXX_Muon::BMSxMDTxx_pv_ZZZ_NAME
133 // where WWW is ass. istance nr.
134 // XXX is comp. imprint nr.
135 // BMSxMDTxx is the name of the comp. log.Vol.
136 // x station sub-type; xx technology subtype
137 // ZZZ is the comp. number of order
138 // NAME is the comp. tag (geoIdentifierTag)
139 // for RPCs it is SwapdbPdbRdbZ[aaa]
140 // with aaa = doubletZ + doubletR*100 + dbphi*1000;
141 // aaa = -aaa if iswap == -1
142 // dbphi = 1 always but for S1 or S2 at doubletPhi = 2
143 // copy numbers for Ass.components are =
144 // CopyNoBase(= geoIdentifierTag of the assembly) + geoIdentifierTag of the component
145 // geoIdentifierTag of the component = Job
146 // geoIdentifierTag of the assembly = (sideC*10000 +
147 // mirsign*1000 + abs(zi)*100 + fi+1)*100000;
148 // mirsign = 1 if zi<0 and !mirrored; otherwise 0
149 std::string::size_type loc1,loc2;
150 if ((loc1 = volName.find("Muon::")) != std::string::npos) {
151 stationName = volName.substr(loc1+6,4); //type and subtype
152 }
153
154 int volCopyNo = touchHist->GetVolume(i)->GetCopyNo();
155 int copyNrBase = int(volCopyNo/100000);
156 int sideC = int(copyNrBase/10000);
157 int zi = int((copyNrBase%1000)/100);
158 int mirfl = int((copyNrBase%10000)/1000);
159 int fi = int(copyNrBase%100);
160 if (sideC == 1) zi = -zi;
161 stationEta = zi;
162 stationPhi = fi;
163 zNeg_original = mirfl;
164
165 if(stationEta<0&&!zNeg_original) station_rotated=1;
166
167 // doubletZ = 1;
168 tech=volName.substr(npos,5);
169
170 // now get the geoIdentifierTag of the rpc components
171 int gmID = 0;
172 if ((loc1 = volName.find('[')) != std::string::npos) {
173 if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
174 //G4cout << "first [ is at "<<loc1<<" first ] at "<<loc2 << G4endl;
175 std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
176 istrvar>>gmID;
177 }
178 }
179 int kk=gmID;
180
181 if (kk < 0) rpcIsRotated=1;
182
183 doubletR =(abs(kk)%1000)/100;
184 mydbZ = abs(int(kk%10));
185 mydbPMod = abs(int(kk/1000));
186 // doubleR, doubletZ
187 } else if ((npos = volName.find("rpccomponent")) != std::string::npos && (!isAssembly)) {
188
189 std::string::size_type loc1,loc2;
190 tech=volName.substr(npos-5,5);
191 int gmID = 0;
192 if ((loc1 = volName.find('[')) != std::string::npos) {
193 if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
194 std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
195 istrvar>>gmID;
196 }
197 }
198 mydbZ = abs(int(gmID%10));
199 mydbPMod = abs(int(gmID/1000));
200
201 int kk=touchHist->GetVolume(i)->GetCopyNo();
202
203 if (kk < 0) rpcIsRotated=1;
204
205 doubletR=(abs(kk)%1000)/100;
206
207 } else if ((npos = volName.find("layer")) != std::string::npos) {
208
209 int copyNo = touchHist->GetVolume(i)->GetCopyNo();
210
211 if (copyNo == 1) {
212 rpcIsRotated ? gasGap = 2 : gasGap = 1;
213 } else if (copyNo ==2) {
214 rpcIsRotated ? gasGap = 1 : gasGap = 2;
215 } else if (copyNo ==3) {
216 gasGap = 3;
217 }
218 } else if((npos = volName.find("gas volume")) != std::string::npos) {
219
220 int copyNo = touchHist->GetVolume(i)->GetCopyNo();
221 if (copyNo == 0) {
222 doubletPhi = 1;
223 } else if (copyNo == 10) {
224 doubletPhi = 2;
225 }
226 mydbP = doubletPhi;
227 int ngap_in_s=0;
228 int nstrippanel_in_s=0;
229 std::string::size_type loc1;
230 if ((loc1 = volName.find("gg_in_s")) != std::string::npos) {
231 std::istringstream istrvar(volName.substr(loc1-1,1));
232 istrvar>>ngap_in_s;
233 }
234 if ((loc1 = volName.find("sp_in_s")) != std::string::npos) {
235 std::istringstream istrvar(volName.substr(loc1-1,1));
236 istrvar>>nstrippanel_in_s;
237 }
238 if (ngap_in_s == 1 && nstrippanel_in_s == 2) {
239 if(localPosition.y()>0) mydbP=2;
240 else mydbP=1;
241 } else if (ngap_in_s == 1 && nstrippanel_in_s == 1) {
242 mydbP = mydbPMod;
243 }
244 }
245 }
246
248 // correct wrong IDs due to station rotation. only doubletZ and doubletPhi are affected at this point
250
251 if(station_rotated){
252 // doubletPhi correction
253 // note that this is correct also for ribs chambers
254 mydbP++;
255 if (mydbP>2) mydbP=1;
256 // G4cout << "Rcd PC - swap dbPhi because ch is MIRRORED "<<doubletPhi << G4endl;
257
258 // strip numbering: if the station is rotated both eta and phi directions get inversed.
259 // commented out for geomodel!
260 }
261
263
264 // now we have the position in the gas gap, with correct axis orientation, and the offlineIDs *of the strip panel*
265 // nstrip is supposed to be calculated by RPC_Digitizer.
266
267 // construct two (one in eta and one in phi) new RPC hits and store them in hit collection
268
269 //construct the hit identifiers
270 if (verboseLevel>5) {
271 G4cout << "hit in station "<<stationName<< " on technology "<<tech << G4endl;
272 G4cout << "constructing ids (stName, stEta, stPhi, dr, dZ, dPhi)= "<<stationName<< " "<< stationEta<<" " << stationPhi<< " "<<doubletR<< " "<< mydbZ<< " "<<mydbP << G4endl;
273 }
274
275 HitID RPCid_eta = m_muonHelper->BuildRpcHitId(stationName, stationPhi, stationEta,
276 mydbZ, doubletR, gasGap, mydbP,0);
277
278 HitID RPCid_phi = m_muonHelper->BuildRpcHitId(stationName, stationPhi, stationEta,
279 mydbZ, doubletR, gasGap, mydbP,1);
280
281 // retrieve track barcode
282 TrackHelper trHelp(aStep->GetTrack());
283
284 //construct new rpc hit
285 m_myRPCHitColl->Emplace(RPCid_eta, globalTime,
286 localPosition,
287 trHelp.GenerateParticleLink(m_g4UserEventInfo ? m_g4UserEventInfo->GetEventStore() : nullptr),
288 localPostPosition,
289 aStep->GetTotalEnergyDeposit(),
290 aStep->GetStepLength(),
291 track->GetDefinition()->GetPDGEncoding(),
292 aStep->GetPreStepPoint()->GetKineticEnergy());
293 m_myRPCHitColl->Emplace(RPCid_phi, globalTime,
294 localPosition,
295 trHelp.GenerateParticleLink(m_g4UserEventInfo ? m_g4UserEventInfo->GetEventStore() : nullptr),
296 localPostPosition,
297 aStep->GetTotalEnergyDeposit(),
298 aStep->GetStepLength(),
299 track->GetDefinition()->GetPDGEncoding(),
300 aStep->GetPreStepPoint()->GetKineticEnergy());
301
302 return true;
303}
int HitID
AtlasHitsVector< RPCSimHit > RPCSimHitCollection
static AtlasG4EventUserInfo * GetEventUserInfo()
RPCSensitiveDetector(const std::string &name, const std::string &hitCollectionName, unsigned int nGasGaps)
construction/destruction
std::string m_hitCollectionName
member data
G4bool ProcessHits(G4Step *, G4TouchableHistory *) override final
const RpcHitIdHelper * m_muonHelper
void Initialize(G4HCofThisEvent *) override final
member functions
AtlasG4EventUserInfo * m_g4UserEventInfo
RPCSimHitCollection * m_myRPCHitColl
static const RpcHitIdHelper * GetHelper(unsigned int nGasGaps=2)
HepMcParticleLink GenerateParticleLink()
Generates a new HepMcParticleLink object on the stack based on the generation-zero unique id,...
Definition TrackHelper.h:75
double angle(const Amg::Vector3D &v1, const Amg::Vector3D &v2)
calculates the opening angle between two vectors
Amg::Vector3D Hep3VectorToEigen(const CLHEP::Hep3Vector &CLHEPvector)
Converts a CLHEP-based CLHEP::Hep3Vector into an Eigen-based Amg::Vector3D.
Eigen::Matrix< double, 3, 1 > Vector3D