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 20 of file RPCSensitiveDetector.cxx.

21  : G4VSensitiveDetector( name )
22  , m_myRPCHitColl( hitCollectionName )
23 {
25 }

◆ ~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 27 of file RPCSensitiveDetector.cxx.

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

◆ ProcessHits()

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

RPCs sensitive to charged particle only

Definition at line 36 of file RPCSensitiveDetector.cxx.

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

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:129
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
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
ZDC::sideC
BySideTypeMod sideC(-1)
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:10
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:41
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:41
TrackHelper
Definition: TrackHelper.h:14
lumiFormat.i
int i
Definition: lumiFormat.py:92
trigbs_pickEvents.num
num
Definition: trigbs_pickEvents.py:76
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
checkFileSG.fi
fi
Definition: checkFileSG.py:65
createCablingJSON.doubletPhi
int doubletPhi
Definition: createCablingJSON.py:11
xAOD::track
@ track
Definition: TrackingPrimitives.h:512
Muon::nsw::STGTPSegments::moduleIDBits::stationEta
constexpr uint8_t stationEta
1 to 3
Definition: NSWSTGTPDecodeBitmaps.h:127
HitID
int HitID
Definition: GenericMuonSimHit.h:13
Trk::loc1
@ loc1
Definition: ParamDefs.h:40