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