GEMC  2.3
Geant4 Monte-Carlo Framework
sensitiveDetector.cc
Go to the documentation of this file.
1 // G4 headers
2 #include "G4SDManager.hh"
3 #include "G4UnitsTable.hh"
4 #include "G4ParticleTypes.hh"
5 #include "G4VProcess.hh"
6 
7 // gemc headers
8 #include "identifier.h"
9 #include "sensitiveDetector.h"
10 
11 // CLHEP units
12 #include "CLHEP/Units/PhysicalConstants.h"
13 using namespace CLHEP;
14 
15 sensitiveDetector::sensitiveDetector(G4String name, goptions opt, string factory, int run, string variation, string system):G4VSensitiveDetector(name), gemcOpt(opt), HCID(-1)
16 {
17  HCname = name;
18  collectionName.insert(HCname);
19  hitCollection = NULL;
20 
21  hd_msg1 = gemcOpt.optMap["LOG_MSG"].args + " New Hit: <<< ";
22  hd_msg2 = gemcOpt.optMap["LOG_MSG"].args + " > ";
23  hd_msg3 = gemcOpt.optMap["LOG_MSG"].args + " End of Hit Collections >> ";
24  catch_v = gemcOpt.optMap["CATCH"].args;
25  verbosity = gemcOpt.optMap["HIT_VERBOSITY"].arg;
26  RECORD_PASSBY = gemcOpt.optMap["RECORD_PASSBY"].arg;
27  RECORD_MIRROR = gemcOpt.optMap["RECORD_MIRRORS"].arg;
28 
29  // when background is being saved, all tracks passing by detectors
30  // are saved even if they do not deposit energy
31  if(gemcOpt.optMap["SAVE_ALL_MOTHERS"].arg == 3)
32  RECORD_PASSBY = 1;
33 
34  SDID = sensitiveID(HCname, gemcOpt, factory, variation, system);
35 }
36 
38 
39 
40 void sensitiveDetector::Initialize(G4HCofThisEvent* HCE)
41 {
42  Id_Set.clear();
43  hitCollection = new MHitCollection(HCname, collectionName[0]);
44  if(HCID < 0) HCID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]);
45  HCE->AddHitsCollection( HCID, hitCollection );
46  ProcessHitRoutine = NULL;
47  if(verbosity > 1)
48  cout << " > " << collectionName[0] << " initialized." << endl;
49 }
50 
51 
52 
53 G4bool sensitiveDetector::ProcessHits(G4Step* aStep, G4TouchableHistory*)
54 {
55  // First check on energy deposited
56  double depe = aStep->GetTotalEnergyDeposit();
57  // don't enter if RECORD_PASSBY is not set and it's not an optical photon
58  // Notice: a gamma will not directly release energy on a scintillator
59  // but will convert, and the pair will release energy
60  // so by default right now gammas are not recorded and the hit belongs to the pair
61 
62  G4VTouchable* THH = (G4VTouchable*) aStep->GetPreStepPoint()->GetTouchable();
63  string aname = THH->GetVolume(0)->GetName();
64 
65  if(depe == 0 && RECORD_PASSBY == 0 && aStep->GetTrack()->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition())
66  return false;
67 
68 
69  // do not record Mirrors unless specified
70  if(HCname == "mirror" && RECORD_MIRROR == 0) return false;
71 
72  G4Track *trk = aStep->GetTrack();
73  if(trk->GetDefinition()->GetParticleName().find("unknown") != string::npos) return false;
74 
75  G4StepPoint *prestep = aStep->GetPreStepPoint();
76  G4StepPoint *poststep = aStep->GetPostStepPoint();
77  string processName = "na";
78 
79  G4VTouchable* TH = (G4VTouchable*) aStep->GetPreStepPoint()->GetTouchable();
80 
84  double Dx = aStep->GetStepLength();
85  string name = TH->GetVolume(0)->GetName();
86  G4ThreeVector xyz = poststep->GetPosition();
87  G4ThreeVector Lxyz = prestep->GetTouchableHandle()->GetHistory()
88  ->GetTopTransform().TransformPoint(xyz);
89  G4ThreeVector vert = trk->GetVertexPosition();
90  double ctime = poststep->GetGlobalTime();
91  G4ThreeVector pxyz = prestep->GetMomentum();
92  double ene = prestep->GetTotalEnergy();
93  int tid = trk->GetTrackID();
94  int pid = trk->GetDefinition()->GetPDGEncoding();
95  int q = (int) trk->GetDefinition()->GetPDGCharge();
96  if(trk->GetCreatorProcess())
97  processName = trk->GetCreatorProcess()->GetProcessName();
98  string materialName = poststep->GetMaterial()->GetName();
99  vector<identifier> VID = SetId(GetDetectorIdentifier(name), TH,
100  ctime, SDID.timeWindow, tid);
101 
102  // Get the ProcessHitRoutine to calculate the new vector<identifier>
103  if(ProcessHitRoutine == NULL)
104  {
105  ProcessHitRoutine = getHitProcess(hitProcessMap, GetDetectorHitType(name));
106  }
107 
108  // if not existing, exit
109  // this should never happen though
110  if(ProcessHitRoutine == NULL)
111  {
112  cout << endl << " !!! Error: >" << name << "< NOT FOUND IN ProcessHit Map. Exiting" << endl;
113  return false;
114  }
115 
118  vector<identifier> PID = ProcessHitRoutine->processID(VID, aStep, (*hallMap)[name]);
119  int singl_hit_size = VID.size();
120  int multi_hit_size = PID.size()/singl_hit_size;
121 
122  // splitting PIDs into an array
123  for(int mh = 0; mh<multi_hit_size; mh++)
124  {
125  vector<identifier> mhPID;
126 
127  for(int this_id = 0; this_id<singl_hit_size; this_id++)
128  {
129  identifier this_shit; // adding this single hit
130  this_shit.name = PID[this_id + mh*singl_hit_size].name;
131  this_shit.rule = PID[this_id + mh*singl_hit_size].rule;
132  this_shit.id = PID[this_id + mh*singl_hit_size].id;
133  this_shit.time = PID[this_id + mh*singl_hit_size].time;
134  this_shit.TimeWindow = PID[this_id + mh*singl_hit_size].TimeWindow;
135  this_shit.TrackId = PID[this_id + mh*singl_hit_size].TrackId;
136  this_shit.id_sharing = PID[this_id + mh*singl_hit_size].id_sharing;
137  mhPID.push_back(this_shit);
138  }
139 
140  if(verbosity > 9 || name.find(catch_v) != string::npos)
141  cout << endl << hd_msg2 << " Before hit Process Identification:" << endl << VID
142  << hd_msg2 << " After: hit Process Identification:" << endl << mhPID << endl;
143 
145  if(verbosity > 9) cout << endl << endl << " BEGIN SEARCH for same hit in Identifier Set..." << endl;
146 
147  set<vector<identifier> > :: iterator itid;
148  int hit_found = 0;
149 
150  for(itid = Id_Set.begin(); itid!= Id_Set.end() && !hit_found; itid++)
151  {
152  if(*itid == mhPID) hit_found=1;
153  if(verbosity > 9 )
154  cout << " >> Current Step: " << mhPID
155  << " >> Set Hit Index: " << *itid
156  << (hit_found ? " >> FOUND at this Set Entry. " : " >> Not found yet. ") << endl;
157  }
158  if(verbosity > 10) cout << " SEARCH ENDED." << (hit_found ? " 1 " : " No ") << "hit found in the Set." << endl << endl;
159 
160 
161 
162  // New Hit
163  if(!hit_found)
164  {
165  MHit *thisHit = new MHit();
166  thisHit->SetPos(xyz);
167  thisHit->SetLPos(Lxyz);
168  thisHit->SetVert(vert);
169  thisHit->SetTime(ctime);
170  thisHit->SetEdep(depe*mhPID[singl_hit_size-1].id_sharing);
171  thisHit->SetDx(Dx);
172  thisHit->SetMom(pxyz);
173  thisHit->SetE(ene);
174  thisHit->SetTrackId(tid);
175  thisHit->SetDetector((*hallMap)[name]);
176  thisHit->SetId(mhPID);
177  thisHit->SetPID(pid);
178  thisHit->SetCharge(q);
179  thisHit->SetMatName(materialName);
180  thisHit->SetProcID(processID(processName));
181  thisHit->SetSDID(SDID);
182  hitCollection->insert(thisHit);
183  Id_Set.insert(mhPID);
184 
185  if(verbosity > 6 || name.find(catch_v) != string::npos)
186  {
187  string pid = aStep->GetTrack()->GetDefinition()->GetParticleName();
188  cout << endl << hd_msg1 << endl
189  << " > This element was not hit yet in this event. Identity:" << endl << thisHit->GetId()
190  << " > Creating new hit by a E=" << ene/MeV << ", p=" << pxyz.mag()/MeV << " MeV " << pid
191  << ", track ID = " << tid << ", inside Hit Collection <" << HCname << ">." << endl
192  << " > Energy Deposited this step: " << depe/MeV << " MeV" << endl
193  << " > Time of this step: " << G4BestUnit(ctime, "Time") << endl
194  << " > Position of this step: " << xyz/cm << " cm" << endl
195  << " > Local Position in volume: " << Lxyz/cm << " cm" << endl;
196  }
197  }
198  else
199  {
200  // Adding hit info only if the poststeppint remains in the volume?
201  // if( aStep->GetPreStepPoint()->GetTouchable()->GetVolume(0) == aStep->GetPostStepPoint()->GetTouchable()->GetVolume(0))
202  {
203  MHit *thisHit = find_existing_hit(mhPID);
204  if(!thisHit)
205  {
206  cout << " Hit not found in collection but found in PID. This should never happen. Exiting." << endl;
207  exit(0);
208  }
209  else
210  {
211  thisHit->SetPos(xyz);
212  thisHit->SetLPos(Lxyz);
213  thisHit->SetVert(vert);
214  thisHit->SetTime(ctime);
215  thisHit->SetEdep(depe*mhPID[singl_hit_size-1].id_sharing);
216  thisHit->SetDx(Dx);
217  thisHit->SetMom(pxyz);
218  thisHit->SetE(ene);
219  thisHit->SetTrackId(tid);
220  thisHit->SetPID(pid);
221  thisHit->SetCharge(q);
222  thisHit->SetMatName(materialName);
223  thisHit->SetProcID(processID(processName));
224  thisHit->SetDetector((*hallMap)[name]);
225 
226  if(verbosity > 6 || name.find(catch_v) != string::npos)
227  {
228  string pid = aStep->GetTrack()->GetDefinition()->GetParticleName();
229  cout << hd_msg2 << " Step Number " << thisHit->GetPos().size()
230  << " inside Identity: " << endl << thisHit->GetId()
231  << " > Adding hit inside Hit Collection <" << HCname << ">."
232  << " by a E=" << ene/MeV << ", p=" << pxyz.mag()/MeV << " MeV "
233  << pid << ", track ID = " << tid << endl
234  << " > Energy Deposited this step: " << depe/MeV << " MeV" << endl
235  << " > Time of this step: " << G4BestUnit(ctime, "Time")
236  << " is within this element Time Window of " << SDID.timeWindow/ns << " ns. " << endl
237  << " > Position of this step: " << xyz/cm << " cm" << endl
238  << " > Local Position in volume: " << Lxyz/cm << " cm" << endl;
239  }
240  }
241  }
242  }
243  }
244 
245 
246  return true;
247 }
248 
249 
250 void sensitiveDetector::EndOfEvent(G4HCofThisEvent *HCE)
251 {
252  int nhitC = hitCollection->GetSize();
253  if(!nhitC) return;
254  MHit *aHit;
255  double Etot;
256  if(verbosity > 2 && nhitC)
257  {
258  cout << endl;
259  cout << hd_msg3 << " Hit Collections <" << HCname << ">: " << nhitC << " hits." << endl;
260 
261  for (int i=0; i<nhitC; i++)
262  {
263  aHit = (*hitCollection)[i];
264  string vname = aHit->GetId()[aHit->GetId().size()-1].name;
265  if(verbosity > 5 || vname.find(catch_v) != string::npos)
266  {
267  cout << hd_msg3 << " Hit " << i + 1 << " -- total number of steps this hit: " << aHit->GetPos().size() << endl;
268  cout << aHit->GetId();
269  Etot = 0;
270  for(unsigned int e=0; e<aHit->GetPos().size(); e++) Etot = Etot + aHit->GetEdep()[e];
271  cout << " Total energy deposited: " << Etot/MeV << " MeV" << endl;
272  }
273  }
274  }
275  if(ProcessHitRoutine) delete ProcessHitRoutine; // not needed anymore
276 
277 }
278 
279 
281 {
282  for(unsigned int i=0; i<hitCollection->GetSize(); i++)
283  if((*hitCollection)[i]->GetId() == PID) return (*hitCollection)[i];
284 
285  return NULL;
286 }
287 
288 // to check process name go to $G4ROOT/$GEANT4_VERSION/source/geant$GEANT4_VERSION/source/processes/
289 // mgrep "const G4String&" | grep process
290 
291 int sensitiveDetector::processID(string procName)
292 {
293  if(procName == "eIoni") return 1;
294  if(procName == "compt") return 2;
295  if(procName == "eBrem") return 3;
296  if(procName == "phot") return 4;
297  if(procName == "conv") return 5;
298  if(procName == "annihil") return 6;
299  if(procName == "photonNuclear") return 7;
300  if(procName == "electronNuclear") return 8;
301  if(procName == "hadElastic") return 9;
302  if(procName == "protonInelastic") return 10;
303  if(procName == "neutronInelastic") return 11;
304  if(procName == "pi-Inelastic") return 12;
305  if(procName == "pi+Inelastic") return 13;
306  if(procName == "hIoni") return 14;
307  if(procName == "nCapture") return 15;
308  if(procName == "Decay") return 16;
309  if(procName == "muIoni") return 17;
310  if(procName == "CoulombScat") return 18;
311  if(procName == "Cerenkov") return 19;
312  if(procName == "dInelastic") return 20;
313  if(procName == "muPairProd") return 21;
314  if(procName == "ionIoni") return 22;
315  if(procName == "hPairProd") return 23;
316  if(procName == "tInelastic") return 24;
317  if(procName == "kaon-Inelastic") return 25;
318 
319  if(procName == "na") return 90;
320 
321  cout << " process name " << procName << " not catalogued." << endl;
322  return 99;
323 }
324 
325 
326 
327 
vector< identifier > SetId(vector< identifier > Iden, G4VTouchable *TH, double time, double TimeWindow, int TrackId)
Sets the ncopy ID accordingly to Geant4 Volumes copy number. Sets time, TimeWindow, TrackId.
Definition: identifier.cc:74
virtual void EndOfEvent(G4HCofThisEvent *)
Virtual Method called at the end of each hit event.
sensitiveID SDID
sensitiveID used for identification, hit properties and digitization
G4String HCname
Sensitive Detector/Hit Collection Name.
MHit * find_existing_hit(vector< identifier >)
returns hit collection hit inside identifer
void SetPos(G4ThreeVector xyz)
Definition: Hit.h:71
vector< identifier > GetId()
Definition: Hit.h:103
vector< identifier > GetDetectorIdentifier(string name)
returns detector identity
virtual vector< identifier > processID(vector< identifier >, G4Step *, detector)=0
int id
manually assing ID. 0 if "ncopy" (will be set at hit processing time)
Definition: identifier.h:39
goptions gemcOpt
gemc option class
string name
Name of the detector.
Definition: identifier.h:37
void SetDetector(detector det)
Definition: Hit.h:106
int processID(string procName)
void SetTrackId(int tid)
Definition: Hit.h:99
map< string, HitProcess_Factory > * hitProcessMap
Hit Process Routine Factory Map.
void SetEdep(double depe)
Definition: Hit.h:82
void SetPID(int pid)
Definition: Hit.h:110
double TimeWindow
Time Window. If abs(steptime - time) is smaller than TimeWindow, it&#39;s the same hit.
Definition: identifier.h:41
virtual void Initialize(G4HCofThisEvent *)
Virtual Method called at the beginning of each hit event.
int TrackId
If Time Window is 0, it&#39;s a "flux" detector: if it&#39;s the same track, it&#39;s the same hit...
Definition: identifier.h:42
void SetMom(G4ThreeVector pxyz)
Definition: Hit.h:91
void SetDx(double Dx)
Definition: Hit.h:85
vector< G4ThreeVector > GetPos()
Definition: Hit.h:72
void SetProcID(int procID)
Definition: Hit.h:144
map< string, aopt > optMap
Options map.
Definition: options.h:75
set< vector< identifier > > Id_Set
Identifier Set. Used to determine if a step is inside a new/existing element.
void SetE(double ene)
Definition: Hit.h:95
G4THitsCollection< MHit > MHitCollection
Definition: Hit.h:194
void SetId(vector< identifier > iden)
Definition: Hit.h:104
Definition: Hit.h:22
void SetCharge(int Q)
Definition: Hit.h:114
double timeWindow
If two steps happens within the same TimeWindow, they belong to the same Hit.
Definition: sensitiveID.h:31
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *)
Virtual Method called for each step of each hit.
double id_sharing
A single step can generate multiple identifiers. This variable represent the percentage sharing of th...
Definition: identifier.h:43
map< string, detector > * hallMap
detector map
double time
Time of the first step.
Definition: identifier.h:40
void SetSDID(sensitiveID s)
Definition: Hit.h:149
virtual ~sensitiveDetector()
void SetLPos(G4ThreeVector xyz)
Definition: Hit.h:75
void SetMatName(string mname)
Definition: Hit.h:139
string GetDetectorHitType(string name)
returns detector hitType
sensitiveDetector(G4String, goptions, string factory, int run, string variation, string system)
Constructor.
void SetTime(double ctime)
Definition: Hit.h:88
vector< double > GetEdep()
Definition: Hit.h:83
void SetVert(G4ThreeVector ver)
Definition: Hit.h:78
string rule
"manual" or "ncopy"
Definition: identifier.h:38
HitProcess * getHitProcess(map< string, HitProcess_Factory > *hitProcessMap, string HCname)
Definition: HitProcess.cc:8