GGS(GenericGEANT4Simulation)Software  2.7.0
 All Data Structures Namespaces Files Functions Variables Typedefs Macros
GGSIntHitSD.cpp
4 #include "montecarlo/scoring/GGSIntHitSDMessenger.h"
5 #include "montecarlo/scoring/GGSTouchableIDComputer.h"
6 #include "utils/GGSFactory.h"
7 #include "utils/GGSStringUtils.h"
8 
9 #include "G4PVReplica.hh"
10 #include "G4SDManager.hh"
11 #include "G4Step.hh"
12 #include "G4TouchableHandle.hh"
13 #include "G4TransportationManager.hh"
14 #include "G4VProcess.hh"
15 #include "G4ios.hh"
16 
17 #include <boost/unordered_map.hpp>
18 
19 #include <numeric>
20 
22 
24  : G4VSensitiveDetector(name), _intHitCollection(NULL), _timeBins(0), _intHitClass("GGSIntHit"),
25  _partHitClass("GGSPartHit"), _posHitClass("GGSPosHit"), _storePartHits(false), _storePosHits(false),
26  _idComputer(nullptr), _intHitThreshold{0.}, _partHitThreshold{0.}, _posHitThreshold{0.}, _currPartHit{nullptr} {
27 
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  } else {
44  throw std::runtime_error(
45  std::string("[GGSIntHitSD::GGSIntHitSD] Missing definition of custom integrated hit class in \"") + params +
46  ("\""));
47  }
48 
49  start = params.find_first_of('[', end + 1);
50  end = params.find_first_of(']', start + 1);
51  if (start != std::string::npos && end != std::string::npos) {
52  partHitClassName = params.substr(start + 1, end - start - 1);
53  } else {
54  throw std::runtime_error(
55  std::string("[GGSIntHitSD::GGSIntHitSD] Missing definition of custom particle hit class in \"") + params +
56  ("\""));
57  }
58 
59  start = params.find_first_of('[', end + 1);
60  end = params.find_first_of(']', start + 1);
61  if (start != std::string::npos && end != std::string::npos) {
62  posHitClassName = params.substr(start + 1, end - start - 1);
63  } else {
64  throw std::runtime_error(
65  std::string("[GGSIntHitSD::GGSIntHitSD] Missing definition of custom position hit class in \"") + params +
66  ("\""));
67  }
68 
69  if (intHitClassName.size() > 0) {
71  if (std::find(buildersList.begin(), buildersList.end(), intHitClassName) == buildersList.end()) {
72  throw std::runtime_error(std::string("[GGSIntHitSD::GGSIntHitSD] Integrated hit class \"") + intHitClassName +
73  "\" not found.");
74  }
75  _intHitClass = intHitClassName;
76  }
77  if (partHitClassName.size() > 0) {
79  if (std::find(buildersList.begin(), buildersList.end(), partHitClassName) == buildersList.end()) {
80  throw std::runtime_error(std::string("[GGSIntHitSD::GGSIntHitSD] Particle hit class \"") + partHitClassName +
81  "\" not found.");
82  }
83  _partHitClass = partHitClassName;
84  }
85  if (posHitClassName.size() > 0) {
87  if (std::find(buildersList.begin(), buildersList.end(), posHitClassName) == buildersList.end()) {
88  throw std::runtime_error(std::string("[GGSIntHitSD::GGSIntHitSD] Position hit class \"") + posHitClassName +
89  "\" not found.");
90  }
91  _posHitClass = posHitClassName;
92  }
93  }
94  }
95 
96  // Create the default ID computer
97  SetTouchableIDComputer("GGSUniqueTouchableIDComputer");
98 }
99 
100 GGSIntHitSD::~GGSIntHitSD() { delete _messenger; }
101 
102 void GGSIntHitSD::SetTouchableIDComputer(const std::string &tidcClassName) {
103  _idComputer = GGSFactory<GGSTouchableIDComputer>::GetInstance().CreateObject(tidcClassName);
104  if (!_idComputer) {
105  throw std::runtime_error("[GGSIntHitSD::GGSIntHitSD] Touchable ID computer class " + tidcClassName + " not found");
106  }
107 }
108 
109 void GGSIntHitSD::Initialize(G4HCofThisEvent *) {
110 
111  // The hits collection is added to G4HCofThisEvent in EndOfEvent.
112  // It is automatically deleted at the end of the event so it must be recreated every time.
113  // However, G4Allocator should provide fast memory allocation for this purpose.
114  _intHitCollection = new GGSIntHitsCollection(SensitiveDetectorName, collectionName[0]);
115 }
116 
117 G4bool GGSIntHitSD::ProcessHits(G4Step *aStep, G4TouchableHistory *) {
118  static const std::string routineName("GGSIntHitSD::ProcessHits");
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  int touchableID = _idComputer->ComputeTouchableID(aStep);
128  G4TouchableHandle touchable = aStep->GetPreStepPoint()->GetTouchableHandle();
129  G4ThreeVector volPos = touchable->GetTranslation(); // Absolute volume translation
130  G4VPhysicalVolume *physVol = touchable->GetVolume();
131 
132  /* *** Add step to integrated hit *** */
133  GGSIntHit *intHit = nullptr;
134  bool intFound = false;
135  // Search for existing integrated hit for this volume
136  auto nIntHits = _intHitCollection->entries();
137  for (int iHit = nIntHits - 1; iHit >= 0; iHit--) {
138  intHit = (*(_intHitCollection))[iHit];
139  if (physVol == intHit->GetVolume() && touchableID == intHit->GetID() && volPos == intHit->GetAbsTranslation()) {
140  intFound = true;
141  break;
142  }
143  }
144  if (!intFound) {
145  // If we reach this point, then this is a new hit
146  intHit = GGSIntHitFactory::GetInstance().CreateObject(_intHitClass, _timeBins).release();
147  if (!intHit) {
148  throw std::runtime_error(
149  std::string("[GGSIntHitSD::ProcessHits] Can't create integrated hit of class ").append(_intHitClass));
150  }
151  // Set global hit properties
152  intHit->SetAbsTranslation(volPos);
153  intHit->SetID(touchableID);
154  intHit->SetVolume(physVol);
155  intHit->SetPartHitsStorage(_storePartHits);
156  intHit->SetPosHitsStorage(_storePosHits);
157  // Call the user initialization routine
158  intHit->UserInit(aStep);
159  // Insert the new integrated hit into the hit collection
160  _intHitCollection->insert(intHit);
161  }
162  // Add the current step to the hit
163  intHit->AddStep(*aStep);
164 
165  if (_storePartHits) {
166  /* *** Add step to particle hit *** */
167  // Create the particle hit if it does not exists, i.e. on first step inside the sensitive volume.
168  // If a particle entered in the volume in previous step and immediately got stopped but not killed then
169  // IsFirstStepInVolume for the current step will be true, so check also that kinetic energy is non-zero for pre-step
170  if (aStep->IsFirstStepInVolume() && aStep->GetPreStepPoint()->GetKineticEnergy() != 0) {
171  if (_currPartHit != nullptr) {
172  // On first step there must be no current hit
173  throw std::runtime_error("GGSIntHitSD::ProcessHit: existing particle hit on first step in sensitive volume");
174  }
175  _currPartHit = GGSPartHitFactory::GetInstance().CreateObject(_partHitClass).release();
176  if (!_currPartHit) {
177  throw std::runtime_error(
178  std::string("[GGSIntHitSD::ProcessHits] Can't create particle hit of class ").append(_partHitClass));
179  }
180  // Set global hit properties
181  _currPartHit->SetPosHitsStorage(_storePosHits);
182  }
183 
184  if (_currPartHit != nullptr) {
185  // Add the current step to the hit
186  _currPartHit->AddStep(*aStep);
187 
188  // Check if this is the last step in the volume
189  // Do not use aStep->IsLastStepInVolume(); see https://geant4-forum.web.cern.ch/t/last-step-in-a-volume/856
190  if ((aStep->GetPostStepPoint()->GetStepStatus() == G4StepStatus::fGeomBoundary &&
191  aStep->GetTrack()->GetTrackStatus() != G4TrackStatus::fStopButAlive) ||
192  aStep->GetTrack()->GetTrackStatus() == G4TrackStatus::fStopAndKill ||
193  aStep->GetTrack()->GetTrackStatus() == G4TrackStatus::fKillTrackAndSecondaries) {
194  if (_currPartHit->GetEnergyDeposit() > _partHitThreshold) {
195  // Hit above threshold: insert it into the hit collection
196  intHit->GetPartHits()->insert(_currPartHit);
197  } else {
198  // Hit below threshold: delete it
199  delete _currPartHit;
200  }
201  // Do not point at the hit anymore (at this point, it's either stored in the collection or deleted)
202  _currPartHit = nullptr;
203  }
204 
205  if (_storePosHits && aStep->GetTotalEnergyDeposit() > _posHitThreshold) {
206  /* *** Create position hit for current step *** */
207  GGSPosHit *posHit = GGSPosHitFactory::GetInstance().CreateObject(_posHitClass).release();
208  if (!posHit) {
209  throw std::runtime_error(
210  std::string("[GGSIntHitSD::ProcessHits] Can't create position hit of class ").append(_posHitClass));
211  }
212  // Insert the new position hit into the hit collection
213  auto *partHit =
214  (_currPartHit ? _currPartHit : (*(intHit->GetPartHits()))[intHit->GetPartHits()->GetSize() - 1]);
215  partHit->GetPosHits()->insert(posHit);
216  // Set members of the position hit
217  posHit->SetStep(*aStep);
218  }
219  } else {
220  std::vector<std::string> statusNames{
221  "fAlive", "fStopButAlive", "fStopAndKill", "fKillTrackAndSecondaries", "fSuspend", "fPostponeToNextEvent"};
222  COUT(WARNING) << "No particle hit has been created for particle:\n";
223  CCOUT(WARNING) << " - type: "
224  << aStep->GetTrack()->GetDynamicParticle()->GetParticleDefinition()->GetParticleName() << "\n";
225  CCOUT(WARNING) << " - creator process: " << aStep->GetTrack()->GetCreatorProcess()->GetProcessName() << "\n";
226  CCOUT(WARNING) << " - trackID: " << aStep->GetTrack()->GetTrackID() << "\n";
227  CCOUT(WARNING) << " - status: " << statusNames[static_cast<int>(aStep->GetTrack()->GetTrackStatus())] << "\n";
228  CCOUT(WARNING) << " - eDep: " << aStep->GetTotalEnergyDeposit() / CLHEP::MeV << " MeV \n";
229  CCOUT(WARNING) << " - kin. energy (pre) : " << aStep->GetPreStepPoint()->GetKineticEnergy() / CLHEP::MeV
230  << " MeV \n";
231  CCOUT(WARNING) << " - kin. energy (post): " << aStep->GetPostStepPoint()->GetKineticEnergy() / CLHEP::MeV
232  << " MeV \n";
233  CCOUT(WARNING) << " - process (pre) : "
234  << (aStep->GetPreStepPoint()->GetProcessDefinedStep()
235  ? aStep->GetPreStepPoint()->GetProcessDefinedStep()->GetProcessName()
236  : "none")
237  << "\n";
238  CCOUT(WARNING) << " - process (post): "
239  << (aStep->GetPostStepPoint()->GetProcessDefinedStep()
240  ? aStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName()
241  : "none")
242  << "\n";
243  }
244  }
245 
246  return true;
247 }
248 
249 void GGSIntHitSD::EndOfEvent(G4HCofThisEvent *hitCollection) {
250 
251  G4int IHID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]);
252  hitCollection->AddHitsCollection(IHID, _intHitCollection);
253 }
virtual void AddStep(const G4Step &step)
Adds a step to the particle hit.
Definition: GGSIntHit.cpp:93
const G4ThreeVector & GetAbsTranslation()
Getter of absolute position of sensitive element.
Definition: GGSIntHit.h:232
Sensitive detector class for integrated hits.
Definition: GGSIntHitSD.h:29
virtual void AddStep(const G4Step &step)
Adds a step to the particle hit.
Definition: GGSPartHit.cpp:101
G4double GetEnergyDeposit() const
Energy deposit getter.
Definition: GGSPartHit.h:148
GGSPartHitsCollection * GetPartHits()
Getter of container of particle hits.
Definition: GGSIntHit.h:226
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:115
#define COUT(level)
Smart log macro. It writes on stdout only if the specified verbosity level is lesser than the maximum...
Definition: GGSSmartLog.h:76
const std::vector< std::string > & GetListOfRegisteredBuilders()
Gets a vector containing the names of available registered builders.
Definition: GGSFactory.h:110
void SetAbsTranslation(const G4ThreeVector &pos)
Set the position in global coordinates of the sensitive element.
Definition: GGSIntHit.h:144
#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:114
const G4VPhysicalVolume * GetVolume()
Getter for volume.
Definition: GGSIntHit.h:218
Definition of GGS Position Hit.
Definition: GGSPosHit.h:33
virtual void UserInit(G4Step *aStep)
User initialization of hit global properties.
Definition: GGSIntHit.h:89
virtual void SetStep(const G4Step &step)
Definition: GGSPosHit.cpp:60
G4int GetID()
Getter for volume ID.
Definition: GGSIntHit.h:238
#define CCOUT(level)
Smart log utility which prints no header at the beginning of the line.
Definition: GGSSmartLog.h:100
void SetID(G4int id)
Setter for volume ID.
Definition: GGSIntHit.h:176
void SetPosHitsStorage(bool flag)
Turn on or off the storage of position hits.
Definition: GGSPartHit.cpp:121
GGSIntHitSD(G4String name)
Constructor.
Definition: GGSIntHitSD.cpp:23
void Initialize(G4HCofThisEvent *hitCollection)
Initializes the sensitive detector.
void SetVolume(const G4VPhysicalVolume *volume)
Setter for volume.
Definition: GGSIntHit.h:109
~GGSIntHitSD()
Destructor.
G4THitsCollection< GGSIntHit > GGSIntHitsCollection
Alias for G4 template hits collection for GGSIntHit.
Definition: GGSIntHit.h:256
Definition of GGS Integrated Hit.
Definition: GGSIntHit.h:32
static GGSFactory & GetInstance()
Getter method for singleton pointer.
Definition: GGSFactory.h:71
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:132
void SetTouchableIDComputer(const std::string &tidcClassName)
Sets the touchable ID computer class.