ATLAS Offline Software
Public Member Functions | Private Member Functions | Private Attributes | List of all members
RPCSensitiveDetector Class Reference

#include <RPCSensitiveDetector.h>

Inheritance diagram for RPCSensitiveDetector:
Collaboration diagram for RPCSensitiveDetector:

Public Member Functions

 RPCSensitiveDetector (const std::string &name, const std::string &hitCollectionName, unsigned int nGasGaps)
 construction/destruction More...
 
 ~RPCSensitiveDetector ()=default
 
void Initialize (G4HCofThisEvent *) override final
 member functions More...
 
G4bool ProcessHits (G4Step *, G4TouchableHistory *) override final
 

Private Member Functions

 FRIEND_TEST (RPCSensitiveDetectortest, Initialize)
 
 FRIEND_TEST (RPCSensitiveDetectortest, ProcessHits)
 

Private Attributes

SG::WriteHandle< RPCSimHitCollectionm_myRPCHitColl
 member data More...
 
const RpcHitIdHelperm_muonHelper {nullptr}
 

Detailed Description

Author
Andre.nosp@m.a.Di.nosp@m.Simon.nosp@m.e@ce.nosp@m.rn.ch

Class methods and properties

The method RPCSensitiveDetector::ProcessHits is executed by the G4 kernel each time a particle crosses one of the RPC gas gaps. Navigating with the touchableHistory method GetHistoryDepth() through the hierarchy of volumes crossed by the particle, the Sensitive Detector determines the correct set of Simulation Identifiers to associate to each hit. The RPC SimIDs are 32-bit unsigned integers, built using the MuonSimEvent/RpcHitIdHelper class which inherits from the MuonHitIdHelper base class.

We describe here how each field of the identifier is determined.

1) stationName, stationEta, stationPhi: when a volume is found in the hierarchy whose name contains the substring "station", the stationName is extracted from the volume's name. stationEta and stationPhi values are calculated starting from the volume's copy number.

2) doubletR: when a volume is found in the hierarchy whose name contains the substring "rpccomponent", its copy number is used to calulate the doubletR of the hit.

3) gasGap: the substring "layer" is searched through the names of the volumes in the hierarchy. When a the volume is found, its copy number is used, together with the sign of the copy number of the "rpccomponent" to decide what is the correct gasGap value.

4) doubletPhi: when the volume with the substring "gas volume" in its name is found, its copy number is enough to determine the doubletPhi of the hit if the hit is registered in a standard chamber. For special chambers (i.e. chambers with only one gas gap per layer readout by two strip panels per direction, or chambers in the ribs) some a special attribution is done using also the stationName.

5) doubletZ: "gazGap" is the required substring in the volume's name. doubletZ attribution is fairly complicated. For standard chambers it just uses the sign of the copy number of the "rpccomponent", but severa arrangements (based on the stationName and the technology name) are needed for special chambers.

6) the doubletPhi calculated as described above needs one further correction for some chambers to take into account chamber rotation before placement in the spectrometer. This is done just before creating the hit.

notes:

1) presently, chamber efficiency is assumed to be 100% at the level of the Sensitive Detector, i.e. two hits (one in eta and one in phi) are created each time the sensitive detector is created.

2) the hits created as described above contain information about their local position in the gas gap and the simulation identifier of the strip panel

3) the strip number is not assigned by the sensitive detector, and must be calculated by the digitization algorithm.

4) points 2 and 3 are due to the necessity of not introducing any dependency on the geometry description in the Sensitive Detector.

5) the present version of the Sensitive Detector produces hits which are different depending on whether hand coded G4 geometry or GeoModel is used for the geometrical description of the setup. When hand coded geometry is used, both GeoModel and the old MuonDetDescr can be used for digitization (using a proper tag of RPC_Digitization), while if GeoModel is used in the simulation, it must be used also in the digitization.

6) for each hit, the time of flight (the G4 globalTime), is recorded and associated to the hit.

7) the RPCHit object contains: the SimID, the globalTime, the hit local position and the track barcode.

Class methods and properties

The method RPCSensitiveDetector::ProcessHits is executed by the G4 kernel each time a particle crosses one of the RPC gas gaps. Navigating with the touchableHistory method GetHistoryDepth() through the hierarchy of volumes crossed by the particle, the Sensitive Detector determines the correct set of Simulation Identifiers to associate to each hit. The RPC SimIDs are 32-bit unsigned integers, built using the MuonSimEvent/RpcHitIdHelper class which inherits from the MuonHitIdHelper base class.

We describe here how each field of the identifier is determined.

1) stationName, stationEta, stationPhi: when a volume is found in the hierarchy whose name contains the substring "station", the stationName is extracted from the volume's name. stationEta and stationPhi values are calculated starting from the volume's copy number.

2) doubletR: when a volume is found in the hierarchy whose name contains the substring "rpccomponent", its copy number is used to calulate the doubletR of the hit.

3) gasGap: the substring "layer" is searched through the names of the volumes in the hierarchy. When a the volume is found, its copy number is used, together with the sign of the copy number of the "rpccomponent" to decide what is the correct gasGap value.

4) doubletPhi: when the volume with the substring "gas volume" in its name is found, its copy number is enough to determine the doubletPhi of the hit if the hit is registered in a standard chamber. For special chambers (i.e. chambers with only one gas gap per layer readout by two strip panels per direction, or chambers in the ribs) some a special attribution is done using also the stationName.

5) doubletZ: "gazGap" is the required substring in the volume's name. doubletZ attribution is fairly complicated. For standard chambers it just uses the sign of the copy number of the "rpccomponent", but severa arrangements (based on the stationName and the technology name) are needed for special chambers.

6) the doubletPhi calculated as described above needs one further correction for some chambers to take into account chamber rotation before placement in the spectrometer. This is done just before creating the hit.

notes:

1) presently, chamber efficiency is assumed to be 100% at the level of the Sensitive Detector, i.e. two hits (one in eta and one in phi) are created each time the sensitive detector is created.

2) the hits created as described above contain information about their local position in the gas gap and the simulation identifier of the strip panel

3) the strip number is not assigned by the sensitive detector, and must be calculated by the digitization algorithm.

4) points 2 and 3 are due to the necessity of not introducing any dependency on the geometry description in the Sensitive Detector.

5) the present version of the Sensitive Detector produces hits which are different depending on whether hand coded G4 geometry or GeoModel is used for the geometrical description of the setup. When hand coded geometry is used, both GeoModel and the old MuonDetDescr can be used for digitization (using a proper tag of RPC_Digitization), while if GeoModel is used in the simulation, it must be used also in the digitization.

6) for each hit, the time of flight (the G4 globalTime), is recorded and associated to the hit.

7) the RPCHit object contains: the SimID, the globalTime, the hit local position and the track barcode.

Definition at line 96 of file RPCSensitiveDetector.h.

Constructor & Destructor Documentation

◆ RPCSensitiveDetector()

RPCSensitiveDetector::RPCSensitiveDetector ( const std::string &  name,
const std::string &  hitCollectionName,
unsigned int  nGasGaps 
)

construction/destruction

Definition at line 22 of file RPCSensitiveDetector.cxx.

23  : G4VSensitiveDetector( name )
24  , m_myRPCHitColl( hitCollectionName )
25 {
27 }

◆ ~RPCSensitiveDetector()

RPCSensitiveDetector::~RPCSensitiveDetector ( )
default

Member Function Documentation

◆ FRIEND_TEST() [1/2]

RPCSensitiveDetector::FRIEND_TEST ( RPCSensitiveDetectortest  ,
Initialize   
)
private

◆ FRIEND_TEST() [2/2]

RPCSensitiveDetector::FRIEND_TEST ( RPCSensitiveDetectortest  ,
ProcessHits   
)
private

◆ Initialize()

void RPCSensitiveDetector::Initialize ( G4HCofThisEvent *  )
finaloverride

member functions

Definition at line 29 of file RPCSensitiveDetector.cxx.

30 {
31  if (!m_myRPCHitColl.isValid()) m_myRPCHitColl = std::make_unique<RPCSimHitCollection>();
32  //FIXME probably only need to call this bit at start of the event
33  //loop rather than the start of each G4Event.
34  if (verboseLevel>5) G4cout << "Initializing SD" << G4endl;
35 
36 }

◆ ProcessHits()

G4bool RPCSensitiveDetector::ProcessHits ( G4Step *  aStep,
G4TouchableHistory *   
)
finaloverride

RPCs sensitive to charged particle only

Reject hits that are parallel through the gas gap

Definition at line 38 of file RPCSensitiveDetector.cxx.

38  {
39 
40  G4Track* track = aStep->GetTrack();
41 
43  if (track->GetDefinition()->GetPDGCharge() == 0.0) {
44  if (track->GetDefinition()!=G4Geantino::GeantinoDefinition()) {
45  return true;
46  }
47  }
48 
49  const G4TouchableHistory* touchHist = static_cast<const G4TouchableHistory*>(aStep->GetPreStepPoint()->GetTouchable());
50  G4ThreeVector position = aStep->GetPreStepPoint()->GetPosition();
51  G4ThreeVector postPosition = aStep->GetPostStepPoint()->GetPosition();
52  const G4AffineTransform trans = track->GetTouchable()->GetHistory()->GetTopTransform(); // from global to local
53 
54  // necessary to assign correct identifiers
55  int rpcIsRotated = 0;
56  // int layer = 0;
57 
58  std::string tech;
59  // fields for the RPC identifier construction
60  std::string stationName;
61  int stationEta= 0;
62  int stationPhi= 0;
63  int doubletR= 0;
64  // int doubletZ= 0;
65  int doubletPhi= 0;
66  int gasGap= 0;
67  // int eta_inversed=0;
68  // int phi_inversed=0;
69  int station_rotated=0; // tells us if the station was rotated before being positioned.
70  // if =1 we have to correct some IDs
71  int zNeg_original=0; // tells if the station at z<0 was obtained duplicating a station at z>0
72 
73  // RPC hit information
74  double globalTime = aStep->GetPreStepPoint()->GetGlobalTime();
75  Amg::Vector3D localPosition = Amg::Hep3VectorToEigen( trans.TransformPoint(position) );
76  Amg::Vector3D localPostPosition = Amg::Hep3VectorToEigen( trans.TransformPoint(postPosition) );
77  {
78  const Amg::Vector3D stepVector = localPostPosition - localPosition;
80  if (stepVector.mag()>std::numeric_limits<float>::epsilon() &&
81  std::abs(std::abs(Amg::angle(stepVector, Amg::Vector3D::UnitX()))
82  - 90.*Gaudi::Units::deg) < 0.0001* Gaudi::Units::deg) {
83  return true;
84  }
85  }
86  int mydbZ=0;
87  int mydbPMod=0;
88  int mydbP=0;
89  bool isAssembly = false;
90  // scan geometry tree to identify the hit channel
91  for (int i=touchHist->GetHistoryDepth();i>=0;i--) {
92 
93  std::string::size_type npos;
94  std::string volName = touchHist->GetVolume(i)->GetName();
95  std::string num=volName.substr(3,2);
96  if(num[0]==' ') num[0]=0;
97 
98  // check if this station is an assembly
99  if ((npos = volName.find("av_")) != std::string::npos &&
100  (npos = volName.find("impr_")) != std::string::npos) isAssembly = true;
101 
102  // stationName, stationEta, stationPhi
103  if ((npos = volName.find("station")) != std::string::npos && (!isAssembly)) {
104 
105  stationName = volName.substr(0,npos-1);
106 
107  int volCopyNo = touchHist->GetVolume(i)->GetCopyNo();
108 
109  if(abs(volCopyNo/1000)==1){
110  zNeg_original=1;
111  volCopyNo=volCopyNo%1000;
112  }
113 
114  stationEta = volCopyNo/100;
115  stationPhi = abs(volCopyNo%100);
116 
117  if(stationEta<0&&!zNeg_original) station_rotated=1;
118 
119  // stationName, stationEta, stationPhi
120  } else if ((npos = volName.find("RPC")) != std::string::npos && isAssembly) {
121  // vol name for Assembly components are
122  // av_WWW_impr_XXX_Muon::BMSxMDTxx_pv_ZZZ_NAME
123  // where WWW is ass. istance nr.
124  // XXX is comp. imprint nr.
125  // BMSxMDTxx is the name of the comp. log.Vol.
126  // x station sub-type; xx technology subtype
127  // ZZZ is the comp. number of order
128  // NAME is the comp. tag (geoIdentifierTag)
129  // for RPCs it is SwapdbPdbRdbZ[aaa]
130  // with aaa = doubletZ + doubletR*100 + dbphi*1000;
131  // aaa = -aaa if iswap == -1
132  // dbphi = 1 always but for S1 or S2 at doubletPhi = 2
133  // copy numbers for Ass.components are =
134  // CopyNoBase(= geoIdentifierTag of the assembly) + geoIdentifierTag of the component
135  // geoIdentifierTag of the component = Job
136  // geoIdentifierTag of the assembly = (sideC*10000 +
137  // mirsign*1000 + abs(zi)*100 + fi+1)*100000;
138  // mirsign = 1 if zi<0 and !mirrored; otherwise 0
139  std::string::size_type loc1,loc2;
140  if ((loc1 = volName.find("Muon::")) != std::string::npos) {
141  stationName = volName.substr(loc1+6,4); //type and subtype
142  }
143 
144  int volCopyNo = touchHist->GetVolume(i)->GetCopyNo();
145  int copyNrBase = int(volCopyNo/100000);
146  int sideC = int(copyNrBase/10000);
147  int zi = int((copyNrBase%1000)/100);
148  int mirfl = int((copyNrBase%10000)/1000);
149  int fi = int(copyNrBase%100);
150  if (sideC == 1) zi = -zi;
151  stationEta = zi;
152  stationPhi = fi;
153  zNeg_original = mirfl;
154 
155  if(stationEta<0&&!zNeg_original) station_rotated=1;
156 
157  // doubletZ = 1;
158  tech=volName.substr(npos,5);
159 
160  // now get the geoIdentifierTag of the rpc components
161  int gmID = 0;
162  if ((loc1 = volName.find('[')) != std::string::npos) {
163  if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
164  //G4cout << "first [ is at "<<loc1<<" first ] at "<<loc2 << G4endl;
165  std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
166  istrvar>>gmID;
167  }
168  }
169  int kk=gmID;
170 
171  if (kk < 0) rpcIsRotated=1;
172 
173  doubletR =(abs(kk)%1000)/100;
174  mydbZ = abs(int(kk%10));
175  mydbPMod = abs(int(kk/1000));
176  // doubleR, doubletZ
177  } else if ((npos = volName.find("rpccomponent")) != std::string::npos && (!isAssembly)) {
178 
179  std::string::size_type loc1,loc2;
180  tech=volName.substr(npos-5,5);
181  int gmID = 0;
182  if ((loc1 = volName.find('[')) != std::string::npos) {
183  if ((loc2 = volName.find(']', loc1+1)) != std::string::npos) {
184  std::istringstream istrvar(volName.substr(loc1+1,loc2-loc1-1));
185  istrvar>>gmID;
186  }
187  }
188  mydbZ = abs(int(gmID%10));
189  mydbPMod = abs(int(gmID/1000));
190 
191  int kk=touchHist->GetVolume(i)->GetCopyNo();
192 
193  if (kk < 0) rpcIsRotated=1;
194 
195  doubletR=(abs(kk)%1000)/100;
196 
197  } else if ((npos = volName.find("layer")) != std::string::npos) {
198 
199  int copyNo = touchHist->GetVolume(i)->GetCopyNo();
200 
201  if (copyNo == 1) {
202  rpcIsRotated ? gasGap = 2 : gasGap = 1;
203  } else if (copyNo ==2) {
204  rpcIsRotated ? gasGap = 1 : gasGap = 2;
205  } else if (copyNo ==3) {
206  gasGap = 3;
207  }
208  } else if((npos = volName.find("gas volume")) != std::string::npos) {
209 
210  int copyNo = touchHist->GetVolume(i)->GetCopyNo();
211  if (copyNo == 0) {
212  doubletPhi = 1;
213  } else if (copyNo == 10) {
214  doubletPhi = 2;
215  }
216  mydbP = doubletPhi;
217  int ngap_in_s=0;
218  int nstrippanel_in_s=0;
219  std::string::size_type loc1;
220  if ((loc1 = volName.find("gg_in_s")) != std::string::npos) {
221  std::istringstream istrvar(volName.substr(loc1-1,1));
222  istrvar>>ngap_in_s;
223  }
224  if ((loc1 = volName.find("sp_in_s")) != std::string::npos) {
225  std::istringstream istrvar(volName.substr(loc1-1,1));
226  istrvar>>nstrippanel_in_s;
227  }
228  if (ngap_in_s == 1 && nstrippanel_in_s == 2) {
229  if(localPosition.y()>0) mydbP=2;
230  else mydbP=1;
231  } else if (ngap_in_s == 1 && nstrippanel_in_s == 1) {
232  mydbP = mydbPMod;
233  }
234  }
235  }
236 
238  // correct wrong IDs due to station rotation. only doubletZ and doubletPhi are affected at this point
240 
241  if(station_rotated){
242  // doubletPhi correction
243  // note that this is correct also for ribs chambers
244  mydbP++;
245  if (mydbP>2) mydbP=1;
246  // G4cout << "Rcd PC - swap dbPhi because ch is MIRRORED "<<doubletPhi << G4endl;
247 
248  // strip numbering: if the station is rotated both eta and phi directions get inversed.
249  // commented out for geomodel!
250  }
251 
253 
254  // now we have the position in the gas gap, with correct axis orientation, and the offlineIDs *of the strip panel*
255  // nstrip is supposed to be calculated by RPC_Digitizer.
256 
257  // construct two (one in eta and one in phi) new RPC hits and store them in hit collection
258 
259  //construct the hit identifiers
260  if (verboseLevel>5) {
261  G4cout << "hit in station "<<stationName<< " on technology "<<tech << G4endl;
262  G4cout << "constructing ids (stName, stEta, stPhi, dr, dZ, dPhi)= "<<stationName<< " "<< stationEta<<" " << stationPhi<< " "<<doubletR<< " "<< mydbZ<< " "<<mydbP << G4endl;
263  }
264 
266  mydbZ, doubletR, gasGap, mydbP,0);
267 
269  mydbZ, doubletR, gasGap, mydbP,1);
270 
271  // retrieve track barcode
272  TrackHelper trHelp(aStep->GetTrack());
273 
274  //construct new rpc hit
275  m_myRPCHitColl->Emplace(RPCid_eta, globalTime,
276  localPosition, trHelp.GenerateParticleLink(), localPostPosition,
277  aStep->GetTotalEnergyDeposit(),
278  aStep->GetStepLength(),
279  track->GetDefinition()->GetPDGEncoding(),
280  aStep->GetPreStepPoint()->GetKineticEnergy());
281  m_myRPCHitColl->Emplace(RPCid_phi, globalTime,
282  localPosition, trHelp.GenerateParticleLink(), localPostPosition,
283  aStep->GetTotalEnergyDeposit(),
284  aStep->GetStepLength(),
285  track->GetDefinition()->GetPDGEncoding(),
286  aStep->GetPreStepPoint()->GetKineticEnergy());
287 
288  return true;
289 }

Member Data Documentation

◆ m_muonHelper

const RpcHitIdHelper* RPCSensitiveDetector::m_muonHelper {nullptr}
private

Definition at line 112 of file RPCSensitiveDetector.h.

◆ m_myRPCHitColl

SG::WriteHandle<RPCSimHitCollection> RPCSensitiveDetector::m_myRPCHitColl
private

member data

Definition at line 111 of file RPCSensitiveDetector.h.


The documentation for this class was generated from the following files:
Muon::nsw::STGTPSegments::moduleIDBits::stationPhi
constexpr uint8_t stationPhi
station Phi 1 to 8
Definition: NSWSTGTPDecodeBitmaps.h:161
RpcHitIdHelper::GetHelper
static const RpcHitIdHelper * GetHelper(unsigned int nGasGaps=2)
Definition: RpcHitIdHelper.cxx:23
dumpTgcDigiDeadChambers.gasGap
list gasGap
Definition: dumpTgcDigiDeadChambers.py:33
RPCSensitiveDetector::m_muonHelper
const RpcHitIdHelper * m_muonHelper
Definition: RPCSensitiveDetector.h:112
Amg::angle
double angle(const Amg::Vector3D &v1, const Amg::Vector3D &v2)
calculates the opening angle between two vectors
Definition: GeoPrimitivesHelpers.h:41
dumpTgcDigiDeadChambers.stationName
dictionary stationName
Definition: dumpTgcDigiDeadChambers.py:30
RPCSensitiveDetector::m_myRPCHitColl
SG::WriteHandle< RPCSimHitCollection > m_myRPCHitColl
member data
Definition: RPCSensitiveDetector.h:111
createCablingJSON.doubletR
int doubletR
Definition: createCablingJSON.py:15
deg
#define deg
Definition: SbPolyhedron.cxx:17
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:35
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
RpcHitIdHelper::BuildRpcHitId
int BuildRpcHitId(const std::string &, const int, const int, const int, const int, const int, const int, const int) const
Definition: RpcHitIdHelper.cxx:102
python.changerun.kk
list kk
Definition: changerun.py:39
TrackHelper
Definition: TrackHelper.h:14
lumiFormat.i
int i
Definition: lumiFormat.py:85
trigbs_pickEvents.num
num
Definition: trigbs_pickEvents.py:76
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
RPDUtils::sideC
unsigned constexpr int sideC
Definition: RPDUtils.h:15
createCablingJSON.doubletPhi
int doubletPhi
Definition: createCablingJSON.py:16
xAOD::track
@ track
Definition: TrackingPrimitives.h:513
Muon::nsw::STGTPSegments::moduleIDBits::stationEta
constexpr uint8_t stationEta
1 to 3
Definition: NSWSTGTPDecodeBitmaps.h:159
HitID
int HitID
Definition: GenericMuonSimHit.h:13
Trk::loc1
@ loc1
Definition: ParamDefs.h:34