GGS(GenericGEANT4Simulation)Software  2.6.3
 All Data Structures Namespaces Files Functions Variables Typedefs Macros
GGSIntHitSD.cpp
2 #include "montecarlo/scoring/GGSIntHitSDMessenger.h"
5 #include "utils/GGSStringUtils.h"
6 
7 #include "G4Step.hh"
8 #include "G4TouchableHandle.hh"
9 #include "G4PVReplica.hh"
10 #include "G4SDManager.hh"
11 #include "G4ios.hh"
12 #include "G4TransportationManager.hh"
13 
14 #include <boost/unordered_map.hpp>
15 
16 #include <numeric>
17 
18 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
19 
21 
22 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
23 
24 GGSIntHitSD::GGSIntHitSD(G4String name) :
25  G4VSensitiveDetector(name), _intHitCollection(NULL), _timeBins(0), _intHitClass("GGSIntHit"), _partHitClass(
26  "GGSPartHit"), _posHitClass("GGSPosHit"), _storePartHits(false), _storePosHits(false), _intHitThreshold { 0. }, _partHitThreshold {
27  0. }, _posHitThreshold { 0. }, _currPartHit { nullptr } {
28  collectionName.insert(name);
29  _messenger = new GGSIntHitSDMessenger(this);
30 
31  auto params = name.substr(name.find_first_of('.') + 1); // Remove volume name
32  auto secondPointPos = params.find_first_of('.');
33  if (secondPointPos != std::string::npos) {
34  // Parameters have been specified so let's handle them
35  params = params.substr(secondPointPos + 1); // Remove GGSIntHitSD
36  if (params.size() > 0) {
37  // Retrieve hit classes
38  std::string intHitClassName, partHitClassName, posHitClassName;
39  auto start = params.find_first_of('[');
40  auto end = params.find_first_of(']');
41  if (start < std::string::npos && end != std::string::npos) {
42  intHitClassName = params.substr(start + 1, end - start - 1);
43  }
44  else {
45  throw std::runtime_error(
46  std::string("[GGSIntHitSD::GGSIntHitSD] Missing definition of custom integrated hit class in \"") + params
47  + ("\""));
48  }
49 
50  start = params.find_first_of('[', end + 1);
51  end = params.find_first_of(']', start + 1);
52  if (start != std::string::npos && end != std::string::npos) {
53  partHitClassName = params.substr(start + 1, end - start - 1);
54  }
55  else {
56  throw std::runtime_error(
57  std::string("[GGSIntHitSD::GGSIntHitSD] Missing definition of custom particle hit class in \"") + params
58  + ("\""));
59  }
60 
61  start = params.find_first_of('[', end + 1);
62  end = params.find_first_of(']', start + 1);
63  if (start != std::string::npos && end != std::string::npos) {
64  posHitClassName = params.substr(start + 1, end - start - 1);
65  }
66  else {
67  throw std::runtime_error(
68  std::string("[GGSIntHitSD::GGSIntHitSD] Missing definition of custom position hit class in \"") + params
69  + ("\""));
70  }
71 
72  if (intHitClassName.size() > 0) {
74  if (std::find(buildersList.begin(), buildersList.end(), intHitClassName) == buildersList.end()) {
75  throw std::runtime_error(
76  std::string("[GGSIntHitSD::GGSIntHitSD] Integrated hit class \"") + intHitClassName + "\" not found.");
77  }
78  _intHitClass = intHitClassName;
79  }
80  if (partHitClassName.size() > 0) {
82  if (std::find(buildersList.begin(), buildersList.end(), partHitClassName) == buildersList.end()) {
83  throw std::runtime_error(
84  std::string("[GGSIntHitSD::GGSIntHitSD] Particle hit class \"") + partHitClassName + "\" not found.");
85  }
86  _partHitClass = partHitClassName;
87  }
88  if (posHitClassName.size() > 0) {
90  if (std::find(buildersList.begin(), buildersList.end(), posHitClassName) == buildersList.end()) {
91  throw std::runtime_error(
92  std::string("[GGSIntHitSD::GGSIntHitSD] Position hit class \"") + posHitClassName + "\" not found.");
93  }
94  _posHitClass = posHitClassName;
95  }
96  }
97  }
98 }
99 
100 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
101 
103  delete _messenger;
104 }
105 
106 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
107 
108 void GGSIntHitSD::Initialize(G4HCofThisEvent*) {
109 
110  // The hits collection is added to G4HCofThisEvent in EndOfEvent.
111  // It is automatically deleted at the end of the event so it must be recreated every time.
112  // However, G4Allocator should provide fast memory allocation for this purpose.
113  _intHitCollection = new GGSIntHitsCollection(SensitiveDetectorName, collectionName[0]);
114 }
115 
116 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
117 
118 G4bool GGSIntHitSD::ProcessHits(G4Step *aStep, G4TouchableHistory*) {
119 
120  // The G4TouchableHistory argument of this method is non-null only if a readout geometry has been
121  // defined. Since this feature is not supported, it is currently always null.
122  // TODO: investigate the possibility to define a readout geometry
123 
124  if (aStep->GetTotalEnergyDeposit() == 0. && !_storePartHits)
125  return false;
126 
127  G4TouchableHandle touchable = aStep->GetPreStepPoint()->GetTouchableHandle();
128  G4ThreeVector volPos = touchable->GetTranslation(); // Absolute volume translation
129  G4VPhysicalVolume *physVol = touchable->GetVolume();
130 
131  // Build the absolute touchable ID
132  // Definition: the multiplicity of a physical volume is defined as the number of that volumes inside a given mother logical volume.
133  // Definition: given a history, the multiplicity at depth i is the multiplicity of the volume in history at depth i
134  // Definition: given a history, the copy number at depth i is the copy number of the volume in history at depth i
135  // Being N_i and M_i the copy number and multiplicity at depth i, the absolute ID of the touchable at history depth 0 is defined as:
136  // ID = N_0 + M_0*N_1 + M_0*M_1*N_2 + ...
137  // At each step, the product M_0*M_1*N_2*... is stored in the variable totMult.
138 
139  int historyDepth = touchable->GetHistoryDepth();
140  int totMult = 1;
141  int touchableID = 0;
142  // Map to store the multiplicity of each physical volume
143  static boost::unordered_map<G4VPhysicalVolume*, int> multMap;
144 
145  for (int iDepth = 0; iDepth < historyDepth; iDepth++) { // This loop will go up in history up to the daughter of the world volume (i.e. iDepth == historyDepth - 1)
146  touchableID += totMult * touchable->GetCopyNumber(iDepth);
147  // Compute total multiplicity for next step
148  if (iDepth != historyDepth - 1) { // No need to compute the total multiplicity on last step
149  int currVolMult = 0;
150  if (!(touchable->GetVolume(iDepth)->IsReplicated())) {
151  // See if the multiplicity for the current non-replicated volume has been computed before
152  boost::unordered_map<G4VPhysicalVolume*, int>::iterator storedMult = multMap.find(touchable->GetVolume(iDepth));
153  if (storedMult == multMap.end()) {
154  // Compute the multiplicity for non-replicated volumes placed inside the current mother logical
155  G4LogicalVolume *currLogVol = touchable->GetVolume(iDepth)->GetLogicalVolume();
156  G4LogicalVolume *motherLogVol = touchable->GetVolume(iDepth)->GetMotherLogical();
157  int nDaughters = motherLogVol->GetNoDaughters();
158  for (int iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
159  if (motherLogVol->GetDaughter(iDaughter)->GetLogicalVolume() == currLogVol)
160  currVolMult++;
161  }
162  // Store the computed multiplicity
163  multMap[touchable->GetVolume(iDepth)] = currVolMult;
164  }
165  else {
166  // Use the stored multiplicity
167  currVolMult = storedMult->second;
168  }
169  }
170  else {
171  // Use the multiplicity of the replicated volume
172  EAxis axis;
173  G4int nReplicas;
174  G4double width, offset;
175  G4bool consuming;
176  touchable->GetVolume(iDepth)->GetReplicationData(axis, nReplicas, width, offset, consuming);
177  currVolMult = nReplicas;
178  }
179  totMult *= currVolMult;
180 
181  }
182  }
183 
184  /* *** Add step to integrated hit *** */
185  GGSIntHit *intHit = nullptr;
186  bool intFound = false;
187  // Search for existing integrated hit for this volume
188  for (int iHit = 0; iHit < _intHitCollection->entries(); iHit++) {
189  intHit = (*(_intHitCollection))[iHit];
190  if (physVol == intHit->GetVolume() && touchableID == intHit->GetID() && volPos == intHit->GetAbsTranslation()) {
191  intFound = true;
192  break;
193  }
194  }
195  if (!intFound) {
196  // If we reach this point, then this is a new hit
197  intHit = GGSIntHitFactory::GetInstance().CreateObject(_intHitClass, _timeBins).release();
198  if (!intHit) {
199  throw std::runtime_error(
200  std::string("[GGSIntHitSD::ProcessHits] Can't create integrated hit of class ").append(_intHitClass));
201  }
202  // Set global hit properties
203  intHit->SetAbsTranslation(volPos);
204  intHit->SetID(touchableID);
205  intHit->SetVolume(physVol);
206  intHit->SetPartHitsStorage(_storePartHits);
207  intHit->SetPosHitsStorage(_storePosHits);
208  // Insert the new integrated hit into the hit collection
209  _intHitCollection->insert(intHit);
210  }
211  // Add the current step to the hit
212  intHit->AddStep(*aStep);
213 
214  if (_storePartHits) {
215  /* *** Add step to particle hit *** */
216  // Create the particle hit if it does not exists, i.e. on first step inside the sensitive volume.
217  // If a particle entered in the volume in previous step and immediately got stopped but not killed then IsFirstStepInVolume
218  // for the current step will be true, so check also that kinetic energy is non-zero for pre-step
219  if (aStep->IsFirstStepInVolume() && aStep->GetPreStepPoint()->GetKineticEnergy() != 0) {
220  if (_currPartHit != nullptr) {
221  // On first step there must be no current hit
222  throw std::runtime_error("GGSIntHitSD::ProcessHit: existing particle hit on first step in sensitive volume");
223  }
224  _currPartHit = GGSPartHitFactory::GetInstance().CreateObject(_partHitClass).release();
225  // Set global hit properties
226  _currPartHit->SetPosHitsStorage(_storePosHits);
227  }
228  // Add the current step to the hit
229  _currPartHit->AddStep(*aStep);
230 
231  // Check if this is the last step in the volume
232  // Do not use aStep->IsLastStepInVolume(); see https://geant4-forum.web.cern.ch/t/last-step-in-a-volume/856
233  if ((aStep->GetPostStepPoint()->GetStepStatus() == G4StepStatus::fGeomBoundary
234  && aStep->GetTrack()->GetTrackStatus() != G4TrackStatus::fStopButAlive)
235  || aStep->GetTrack()->GetTrackStatus() == G4TrackStatus::fStopAndKill
236  || aStep->GetTrack()->GetTrackStatus() == G4TrackStatus::fKillTrackAndSecondaries) {
237  if (_currPartHit->GetEnergyDeposit() > _partHitThreshold) {
238  // Hit above threshold: insert it into the hit collection
239  intHit->GetPartHits()->insert(_currPartHit);
240  }
241  else {
242  // Hit below threshold: delete it
243  delete _currPartHit;
244  }
245  // Do not point at the hit anymore (at this point, it's either stored in the collection or deleted)
246  _currPartHit = nullptr;
247  }
248 
249  if (_storePosHits && aStep->GetTotalEnergyDeposit() > _posHitThreshold) {
250  /* *** Create position hit for current step *** */
251  GGSPosHit *posHit = GGSPosHitFactory::GetInstance().CreateObject(_posHitClass).release();
252  if (!posHit) {
253  throw std::runtime_error(
254  std::string("[GGSIntHitSD::ProcessHits] Can't create position hit of class ").append(_posHitClass));
255  }
256  // Insert the new position hit into the hit collection
257  auto *partHit = (_currPartHit ? _currPartHit : (*(intHit->GetPartHits()))[intHit->GetPartHits()->GetSize() - 1]);
258  partHit->GetPosHits()->insert(posHit);
259  // Set members of the position hit
260  posHit->SetStep(*aStep);
261  }
262  }
263 
264  return true;
265 }
266 
267 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
268 void GGSIntHitSD::EndOfEvent(G4HCofThisEvent *hitCollection) {
269 
270  G4int IHID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]);
271  hitCollection->AddHitsCollection(IHID, _intHitCollection);
272 
273 }
274 
275 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
virtual void AddStep(const G4Step &step)
Adds a step to the particle hit.
Definition: GGSIntHit.cpp:104
const G4ThreeVector & GetAbsTranslation()
Getter of absolute position of sensitive element.
Definition: GGSIntHit.h:242
Sensitive detector class for integrated hits.
Definition: GGSIntHitSD.h:28
virtual void AddStep(const G4Step &step)
Adds a step to the particle hit.
Definition: GGSPartHit.cpp:110
G4double GetEnergyDeposit() const
Energy deposit getter.
Definition: GGSPartHit.h:144
GGSPartHitsCollection * GetPartHits()
Getter of container of particle hits.
Definition: GGSIntHit.h:234
void EndOfEvent(G4HCofThisEvent *hitCollection)
Sets the hits collection, as required by specifications of mother class.
std::unique_ptr< T > CreateObject(const std::string &name, ConstructorArgs...arguments)
Create an object.
Definition: GGSFactory.h:123
const std::vector< std::string > & GetListOfRegisteredBuilders()
Gets a vector containing the names of available registered builders.
Definition: GGSFactory.h:118
void SetAbsTranslation(const G4ThreeVector &pos)
Set the position in global coordinates of the sensitive element.
Definition: GGSIntHit.h:136
#define RegisterSD(sdClassName)
Macro for registration of sensitive detector classes.
void SetPosHitsStorage(bool flag)
Turn on or off the storage of position hits.
Definition: GGSIntHit.cpp:125
const G4VPhysicalVolume * GetVolume()
Getter for volume.
Definition: GGSIntHit.h:224
Definition of GGS Position Hit.
Definition: GGSPosHit.h:31
virtual void SetStep(const G4Step &step)
Definition: GGSPosHit.cpp:65
G4int GetID()
Getter for volume ID.
Definition: GGSIntHit.h:250
void SetID(G4int id)
Setter for volume ID.
Definition: GGSIntHit.h:170
void SetPosHitsStorage(bool flag)
Turn on or off the storage of position hits.
Definition: GGSPartHit.cpp:130
GGSIntHitSD(G4String name)
Constructor.
Definition: GGSIntHitSD.cpp:24
void Initialize(G4HCofThisEvent *hitCollection)
Initializes the sensitive detector.
void SetVolume(const G4VPhysicalVolume *volume)
Setter for volume.
Definition: GGSIntHit.h:99
~GGSIntHitSD()
Destructor.
G4THitsCollection< GGSIntHit > GGSIntHitsCollection
Alias for G4 template hits collection for GGSIntHit.
Definition: GGSIntHit.h:272
Definition of GGS Integrated Hit.
Definition: GGSIntHit.h:31
static GGSFactory & GetInstance()
Getter method for singleton pointer.
Definition: GGSFactory.h:75
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROHist)
The hit processing method.
The integrated hit SD messenger class.
void SetPartHitsStorage(bool flag)
Turn on or off the storage of particle hits.
Definition: GGSIntHit.cpp:144