GGS(GenericGEANT4Simulation)Software  2.99.0
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Macros
GGSHitsAction.cpp
Go to the documentation of this file.
1 /*
2  * GGSHitsAction.cpp
3  *
4  * Created on: Oct 8, 2010
5  * Author: Elena Vannuccini and Nicola Mori
6  */
7 
15 #include "utils/GGSNameDecoder.h"
16 #include "utils/GGSSmartLog.h"
17 #include "utils/GGSStringUtils.h"
18 
19 #include "G4SDManager.hh"
20 #include "G4SystemOfUnits.hh"
21 #include "G4UIcmdWithAString.hh"
22 #include "G4UnitsTable.hh"
23 
24 #include "TArrayF.h"
25 
26 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
27 
29 
30 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
31 
33  : GGSUserAction(), _messenger(this, "/GGS/userActions/hitsAction/", "Commands for hits action"), _outFileBase(""),
34  _outFile(nullptr), _outTree(nullptr), _outTreeName(""), _privateMessenger(this) {
35 
36  // Setup the messenger
37  _messenger.DeclareProperty("fileBase", _outFileBase)
38  .SetGuidance("Sets the base name for ROOT output file")
39  .SetGuidance(" Can be with or without extension (.root will be used automatically)")
40  .SetStates(G4State_PreInit, G4State_Idle);
41  _messenger.DeclareProperty("treeName", _outTreeName)
42  .SetGuidance("Set the name of the TTree object in the ROOT output file.")
43  .SetStates(G4State_PreInit, G4State_Idle);
44 
45  _messenger.DeclareMethod("outputIntHitClass", &GGSHitsAction::SetOutputIntHitClass)
46  .SetGuidance("Class name of output integrated hits")
47  .SetStates(G4State_PreInit, G4State_Idle);
48  _messenger.DeclareMethod("outputPartHitClass", &GGSHitsAction::SetOutputPartHitClass)
49  .SetGuidance("Class name of output particle hits")
50  .SetStates(G4State_PreInit, G4State_Idle);
51  _messenger.DeclareMethod("outputPosHitClass", &GGSHitsAction::SetOutputPosHitClass)
52  .SetGuidance("Class name of output position hits")
53  .SetStates(G4State_PreInit, G4State_Idle);
54 }
55 
56 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
57 
59  // Let the TObjArry disown their TClonesArrays to avoid a double deletion since they are owned by the
60  // GGSTClonesArrayService.
61  for (auto &handleElem : _outputHandles) {
62  OutputHandle &handle = handleElem.second;
63  if (handle.partHitArray) {
64  handle.partHitArray->SetOwner(false);
65  }
66  if (handle.posHitArray) {
67  handle.posHitArray->SetOwner(false);
68  }
69  }
70 }
71 
72 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
73 
74 void GGSHitsAction::BeginOfRunAction(const G4Run *run) {
75  const std::string routineName("GGSHitsAction::BeginOfRunAction");
76 
77  // -----------------
78  // Open the run file
79  // -----------------
80  _outFile = GGSRootFileService::GetInstance().GetFileForThisRun(_outFileBase, run);
81  if (!_outFile || (_outFile && _outFile->IsZombie())) {
82  GGSCOUT(ERROR) << "Cannot open ROOT file " << _outFileBase << "for run" << run->GetRunID() << GGSENDL;
83  throw -1;
84  }
85 
86  // -----------------
87  // Create a new tree
88  // -----------------
89  if (_outTreeName == "") {
90  _outTree = GGSRootFileService::GetInstance().GetDefaultTree(_outFile);
91  _outTree->SetTitle(TString(_outTree->GetTitle()) + "Hits ");
92  } else
93  _outTree = new TTree(_outTreeName, "GGS hits");
94 
95  // Loop over logical volumes...
96  G4LogicalVolumeStore *logicalVS = G4LogicalVolumeStore::GetInstance();
97  if (!logicalVS)
98  return;
99 
100  std::vector<G4VSensitiveDetector *> processedSDs;
101  for (unsigned int i = 0; i < logicalVS->size(); i++) {
102  G4LogicalVolume *logicalV = logicalVS->at(i);
103 
104  // ...and select sensitive volumes with GGS hits SD
105  std::vector<G4VSensitiveDetector *> sDets(0);
106  G4VSensitiveDetector *sd = logicalV->GetSensitiveDetector();
107  if (sd) {
108  GGSMultiSensitiveDetector *msd = dynamic_cast<GGSMultiSensitiveDetector *>(sd);
109  if (msd) {
110  sDets = msd->GetListOfSensitiveDetectors();
111  } else {
112  sDets.push_back(sd);
113  }
114  }
115 
116  for (auto &sdPtr : sDets) {
117  if (std::find(processedSDs.begin(), processedSDs.end(), sdPtr) != processedSDs.end()) {
118  continue;
119  }
120  auto sdName = sdPtr->GetName();
121  auto ggssdNamePos = sdName.find(".GGSIntHitSD", 0);
122  if (ggssdNamePos != std::string::npos) {
123  GGSIntHitSD *intHitSD = dynamic_cast<GGSIntHitSD *>(sdPtr);
124  if (intHitSD && intHitSD->isActive()) {
125  std::string sdNameReduced = sdName;
126  sdNameReduced.erase(ggssdNamePos, 12); // Remove ".GGSIntHitSD"
127 
128  std::unordered_map<std::string, OutputHandle>::iterator handleIter = _outputHandles.find(sdName);
129  if (handleIter == _outputHandles.end()) {
130  // The handle for this detector does not exist yet, so create a standard one
131 
132  auto insertResult = _outputHandles.insert(std::pair<std::string, OutputHandle>{sdName, OutputHandle()});
133  if (insertResult.second) {
134  handleIter = insertResult.first;
135  }
136  }
137 
138  // Create arrays et al.
139  auto &newHandle = handleIter->second;
140  newHandle.intHitArray = std::unique_ptr<TClonesArray>(new TClonesArray(
141  newHandle.intHitClassName.c_str())); // Create it here and Clear("C") it at beginning of event
142  // Create a branch to store hits in the output file
143  _outTree->Branch((sdNameReduced + "-GGSIntHits").data(), "TClonesArray", newHandle.intHitArray.get(), 64000);
144 
145  // Set output threshold
146  {
147  auto thresholdIter = std::find_if(
148  _thresholds.begin(), _thresholds.end(), [&sdNameReduced](const ThresholdStruct &threshold) {
149  return (threshold.hitType == 0) && (sdNameReduced == threshold.detectorName);
150  });
151  if (thresholdIter != _thresholds.end()) {
152  newHandle.intHitThreshold = thresholdIter->value;
153  }
154  }
155  if (intHitSD->GetPartHitsStorage()) {
156  newHandle.partHitArray = std::unique_ptr<TObjArray>(new TObjArray());
157  // Set ownership to avoid memory leaks when reading back the TObjArray.
158  // http://root.cern.ch/root/roottalk/roottalk02/0444.html
159  newHandle.partHitArray->SetOwner(true);
160  _outTree->Branch((sdNameReduced + "-GGSPartHits").data(), "TObjArray", newHandle.partHitArray.get(), 64000);
161  newHandle.partHitCAService =
162  std::unique_ptr<GGSTClonesArrayService>(new GGSTClonesArrayService(newHandle.partHitClassName.c_str()));
163  // Set output threshold
164  auto thresholdIter = std::find_if(
165  _thresholds.begin(), _thresholds.end(), [&sdNameReduced](const ThresholdStruct &threshold) {
166  return (threshold.hitType == 1) && (sdNameReduced == threshold.detectorName);
167  });
168  if (thresholdIter != _thresholds.end()) {
169  newHandle.partHitThreshold = thresholdIter->value;
170  }
171  }
172  if (intHitSD->GetPosHitsStorage()) {
173  newHandle.posHitArray = std::unique_ptr<TObjArray>(new TObjArray());
174  newHandle.posHitArray->SetOwner(true);
175  _outTree->Branch((sdNameReduced + "-GGSPosHits").data(), "TObjArray", newHandle.posHitArray.get(), 64000);
176  newHandle.posHitCAService =
177  std::unique_ptr<GGSTClonesArrayService>(new GGSTClonesArrayService(newHandle.posHitClassName.c_str()));
178  // Set output threshold
179  auto thresholdIter = std::find_if(
180  _thresholds.begin(), _thresholds.end(), [&sdNameReduced](const ThresholdStruct &threshold) {
181  return (threshold.hitType == 2) && (sdNameReduced == threshold.detectorName);
182  });
183  if (thresholdIter != _thresholds.end()) {
184  newHandle.posHitThreshold = thresholdIter->value;
185  }
186  }
187 
188  // Save the time bins as run products
189  if (GGSRootFileService::GetInstance().GetOutputMode() == GGSRootFileService::OutputMode::MULTIFILE ||
190  G4Threading::G4GetThreadId() <= 0) {
191  unsigned int nBins = intHitSD->GetTimeBins().size();
192  TArrayF timeBins(nBins);
193  for (unsigned int iBin = 0; iBin < nBins; iBin++)
194  timeBins[iBin] = intHitSD->GetTimeBins()[iBin];
195  _outFile->WriteObject(&timeBins, (sdNameReduced + "-GGSIntHits-TimeBins").data());
196 
197  // Save the hit thresholds
198  std::vector<float> detThresholds{(float)(newHandle.intHitThreshold / GeV),
199  (float)(newHandle.partHitThreshold / GeV),
200  (float)(newHandle.posHitThreshold / GeV)};
201  _outFile->WriteObject(&detThresholds, (sdNameReduced + "-GGSIntHits-Thresholds").data());
202  }
203 
204  } // Check on active volume
205 
206  } // Check on sensitive volume name
207  processedSDs.push_back(sdPtr);
208  } // End loop on sensitive detectors
209 
210  } // End loop on logical volumes
211 }
212 
213 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
214 
215 void GGSHitsAction::EndOfRunAction(const G4Run *run) {
216 
217  // -----------------
218  // close output file
219  // -----------------
220 
221  if (_outFile) {
222  _outFile->cd();
223  if (_outTreeName != "") {
224  // Write the tree if we are not using the default one
225  _outTree->Write();
226  }
227 
229  run); // Will automatically save detector informations
230  _outFile = nullptr;
231  _outTree = nullptr; // The tree is delete by the file's destructor.
232  } else {
233  throw -1; // TODO handle errors
234  }
235 
236  // -----------------
237  // delete detectors
238  // -----------------
239 
240  // Prepare for an eventual next run
241  _GiveBackAllArrays();
242  for (auto &handleElem : _outputHandles) {
243  if (handleElem.second.posHitCAService) {
244  handleElem.second.posHitCAService->DeleteAll();
245  }
246  if (handleElem.second.partHitCAService) {
247  handleElem.second.partHitCAService->DeleteAll();
248  }
249  }
250 }
251 
252 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
253 
254 void GGSHitsAction::BeginOfEventAction(const G4Event *) {
255 
256  // Give back arrays to the TCLonesArray services.
257  _GiveBackAllArrays();
258 
259  for (auto &handleElem : _outputHandles) {
260  OutputHandle &handle = handleElem.second;
261  if (handle.partHitArray) {
262 
263  // Clear the TObjarray persistence structures. These contains TClonesArrays which
264  // must not be deleted since they are owned and managed by the GGSTClonesArrayService...
265 
266  // ... so set the TObjArray to not own them...
267  handle.partHitArray->SetOwner(false);
268  // ... then clean to make size=0 without deleting the contained objects...
269  handle.partHitArray->Clear();
270  // ... and then restore ownership to avoid memory leak on readout of ROOT file.
271  // (see http://root.cern.ch/root/roottalk/roottalk02/0444.html)
272  handle.partHitArray->SetOwner(true);
273  }
274 
275  if (handle.posHitArray) {
276  handle.posHitArray->SetOwner(false);
277  handle.posHitArray->Clear();
278  handle.posHitArray->SetOwner(true);
279  }
280  }
281 }
282 
283 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
284 
285 void GGSHitsAction::EndOfEventAction(const G4Event *event) {
286 
287  //-------------------------------
288  // Set hits info
289  //-------------------------------
290 
291  // Retrieve SD manager
292  G4SDManager *SDman = G4SDManager::GetSDMpointer();
293 
294  // Retrieve event hits
295  G4HCofThisEvent *evHitColl = event->GetHCofThisEvent();
296 
297  // Loop on detectors
298  for (auto &handleElem : _outputHandles) {
299 
300  const std::string &detectorName = handleElem.first;
301  OutputHandle &handle = handleElem.second;
302  // Get hits of current detector
303  G4int hitsCollID = SDman->GetCollectionID(detectorName);
304 
305  // Convert hits to persistent data format
306  handle.intHitArray->Clear(); // Set entries to 0 but do not clear elements (will be cleared in _Convert)
307  _Convert(*((GGSIntHitsCollection *)(evHitColl->GetHC(hitsCollID))), *(handle.intHitArray), handle, detectorName);
308 
309  // Link particle and position hit collections to persistence array
310  for (int iIntHit = 0; iIntHit < handle.intHitArray->GetEntries(); ++iIntHit) {
311  GGSTIntHitBase *tIntHit = (GGSTIntHitBase *)(handle.intHitArray->At(iIntHit));
312  if (tIntHit->_partHits) {
313  handle.partHitArray->AddAtAndExpand(tIntHit->_partHits, handle.partHitArray->GetEntries());
314  if (tIntHit->_partHits->GetEntries() > 0 && ((GGSTPartHitBase *)(tIntHit->_partHits->At(0)))->_posHits) {
315  static TClonesArray *partHits = nullptr;
316  static Int_t nPartHits = 0;
317  partHits = tIntHit->_partHits;
318  nPartHits = partHits->GetEntries();
319  for (Int_t iPartHit = 0; iPartHit < nPartHits; iPartHit++) {
320  GGSTPartHitBase *partHit = (GGSTPartHitBase *)(tIntHit->_partHits->At(iPartHit));
321  partHit->_posHitIndex = handle.posHitArray->GetEntries(); // Save reference to pos hit array
322  handle.posHitArray->AddAtAndExpand(partHit->_posHits, handle.posHitArray->GetEntries());
323  }
324  }
325  }
326  }
327  }
328 
329  //-----------
330  // Fill tree
331  //-----------
332  if (_outTreeName != "") {
333  // Call fill only if not using the default tree
334  _outFile->cd();
335  _outTree->Fill();
336  }
337 }
338 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
339 
340 void GGSHitsAction::_Convert(const GGSPosHitsCollection &posHits, TClonesArray &tPosHits, OutputHandle &handle) {
341 
342  if (tPosHits.GetEntries() != 0) {
343  throw std::runtime_error("GGSHitsAction::_Convert: dirty TClonesArray for position hits");
344  }
345  for (size_t iHit = 0, currTPosHit = 0; iHit < posHits.GetSize(); ++iHit) {
346  auto &posHit = *((GGSPosHit *)(posHits.GetHit(iHit)));
347  if (posHit.GetEnergyDeposit() > handle.posHitThreshold) {
348  GGSTPosHitBase &tPosHit = *((GGSTPosHitBase *)(tPosHits.ConstructedAt(currTPosHit, "C"))); // Get a cleared hit
349  tPosHit.eDep = posHit.GetEnergyDeposit() / GeV;
350  tPosHit.UserConversion(posHit);
351  // Increase counter for output position hits
352  ++currTPosHit;
353  }
354  }
355 }
356 
357 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
358 
359 void GGSHitsAction::_Convert(const GGSPartHitsCollection &partHits, TClonesArray &tPartHits, OutputHandle &handle) {
360 
361  if (tPartHits.GetEntries() != 0) {
362  throw std::runtime_error("GGSHitsAction::_Convert: dirty TClonesArray for particle hits");
363  }
364  for (size_t iHit = 0, currTPartHit = 0; iHit < partHits.GetSize(); ++iHit) {
365  auto &partHit = *((GGSPartHit *)(partHits.GetHit(iHit)));
366  const GGSPosHitsCollection *posHitColl = partHit.GetPosHits();
367  auto &tPartHit = *((GGSTPartHitBase *)(tPartHits.ConstructedAt(currTPartHit, "C"))); // Get a cleared hit
368  if (posHitColl) {
369  // Convert the position hits
370  if (!(tPartHit._posHits)) {
371  tPartHit._posHits = handle.posHitCAService->ProvideArray(
372  posHitColl->GetSize()); // Get a hit array with 0 entries and non-cleared elements
373  } else {
374  // The particle hit should have given back its position hits array at BeginOfEvent, so this code
375  // should never be executed. Throw an exception.
376  throw std::logic_error(
377  "GGSHitsAction::_Convert: particle hit already has position hits, this should not happen.");
378  }
379  _Convert(*posHitColl, *(tPartHit._posHits), handle);
380  }
381  // Save the particle hit if its energy deposit is above threshold or if there are position hits above threshold
382  if (partHit.GetEnergyDeposit() > handle.partHitThreshold || (posHitColl && tPartHit._posHits->GetEntries() != 0)) {
383  tPartHit.eDep = partHit.GetEnergyDeposit() / GeV;
384  tPartHit.UserConversion(partHit);
385  // Increase counter for output particle hits
386  ++currTPartHit;
387  } else { // Otherwise remove the particle hit
388  if (tPartHit._posHits) { // Before deleting the particle hit we need to give back the array of position hits
389  handle.posHitCAService->TakeBackArray(tPartHit._posHits);
390  }
391  tPartHits.RemoveLast();
392  }
393  }
394 }
395 
396 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
397 
398 void GGSHitsAction::_Convert(const GGSIntHitsCollection &intHits, TClonesArray &tIntHits, OutputHandle &handle,
399  const std::string &detectorName) {
400 
401  if (tIntHits.GetEntries() != 0) {
402  throw std::runtime_error("GGSHitsAction::_Convert: dirty TClonesArray for particle hits");
403  }
404  for (size_t iHit = 0, currTIntHit = 0; iHit < intHits.GetSize(); ++iHit) {
405  auto &intHit = *((GGSIntHit *)(intHits.GetHit(iHit)));
406  const GGSPartHitsCollection *partHitColl = intHit.GetPartHits();
407  auto &tIntHit = *((GGSTIntHitBase *)(tIntHits.ConstructedAt(currTIntHit, "C"))); // Get a cleared hit
408  if (partHitColl) { // Convert the particle hits
409  if (!tIntHit._partHits) {
410  tIntHit._partHits = handle.partHitCAService->ProvideArray(
411  partHitColl->GetSize()); // Get a hit array with 0 entries and non-cleared elements
412  } else {
413  // The integrated hit should have given back its particle hits array at BeginOfEvent, so this code
414  // should never be executed. Throw an exception.
415  throw std::logic_error(
416  "GGSHitsAction::_Convert: integrated hit already has particle hits, this should not happen.");
417  }
418  _Convert(*partHitColl, *(tIntHit._partHits), handle);
419  }
420 
421  // Save the integrated hit if its energy deposit is above threshold or if there are particle hits
422  auto totEDep = intHit.GetTotalEnergyDep();
423  if (totEDep > handle.intHitThreshold || (partHitColl && tIntHit._partHits->GetEntries() != 0)) {
424  tIntHit.eDep = totEDep / GeV;
425  if (tIntHit.eDepTimeBin.GetSize() != (int)(intHit.GetEnergyDep().size()))
426  tIntHit.eDepTimeBin.Set(intHit.GetEnergyDep().size());
427  for (unsigned int i = 0; i < intHit.GetEnergyDep().size(); i++) {
428  tIntHit.eDepTimeBin[i] = intHit.GetEnergyDep()[i] / GeV;
429  }
430  tIntHit.UserConversion(intHit);
431 
432  // ----- Save volume informations of this hit ------
433  tIntHit._volumeIndex = GGSRootFileService::GetInstance().StoreVolume(_outFile, detectorName, intHit.GetVolume(),
434  intHit.GetAbsTranslation(), intHit.GetID());
435  // Increase counter for output integrated hits
436  ++currTIntHit;
437  } else { // Otherwise remove the integrated hit
438  if (tIntHit._partHits) { // Before deleting the integrated hit we need to give back the array of particle hits
439  handle.partHitCAService->TakeBackArray(tIntHit._partHits);
440  // No need to give back arrays for position hits: this code portion is executed only when no particle hits are
441  // present, so there are no position hits
442  }
443  tIntHits.RemoveLast();
444  }
445  }
446 }
447 
448 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
449 
450 void GGSHitsAction::SetOutputIntHitClass(std::string detectorName, const std::string &className) {
451  const std::string routineName("[GGSHitsAction::SetOutputIntHitClass] ");
452 
453  // Check if the given class has a dictionary
454  TClass *intHitClass = TClass::GetClass(className.c_str());
455  if (!intHitClass) {
456  throw std::runtime_error(routineName + "Dictionary for class " + className + " not found");
457  }
458 
459  // Check if the given detector already has a specified output class
460  detectorName.insert(detectorName.find_first_of('.'), ".GGSIntHitSD");
461  auto handleIter = _outputHandles.find(detectorName);
462  if (handleIter == _outputHandles.end()) {
463  handleIter = _outputHandles.insert(std::pair<std::string, OutputHandle>{detectorName, OutputHandle()}).first;
464  }
465 
466  // Set output facilities
467  handleIter->second.intHitClassName = className;
468 }
469 
470 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
471 
472 void GGSHitsAction::SetOutputPartHitClass(std::string detectorName, const std::string &className) {
473  const std::string routineName("[GGSHitsAction::SetOutputPartHitClass] ");
474 
475  // Check if the given class has a dictionary
476  TClass *partHitClass = TClass::GetClass(className.c_str());
477  if (!partHitClass) {
478  throw std::runtime_error(routineName + "Dictionary for class " + className + " not found");
479  }
480 
481  // Check if the given detector already has a specified output class
482  detectorName.insert(detectorName.find_first_of('.'), ".GGSIntHitSD");
483  auto handleIter = _outputHandles.find(detectorName);
484  if (handleIter == _outputHandles.end()) {
485  handleIter = _outputHandles.insert(std::pair<std::string, OutputHandle>{detectorName, OutputHandle()}).first;
486  }
487 
488  // Set output facilities
489  handleIter->second.partHitClassName = className;
490 }
491 
492 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
493 
494 void GGSHitsAction::SetOutputPosHitClass(std::string detectorName, const std::string &className) {
495  const std::string routineName("[GGSHitsAction::SetOutputPosHitClass] ");
496 
497  // Check if the given class has a dictionary
498  TClass *posHitClass = TClass::GetClass(className.c_str());
499  if (!posHitClass) {
500  throw std::runtime_error(routineName + "Dictionary for class " + className + " not found");
501  }
502 
503  // Check if the given detector already has a specified output class
504  detectorName.insert(detectorName.find_first_of('.'), ".GGSIntHitSD");
505  auto handleIter = _outputHandles.find(detectorName);
506  if (handleIter == _outputHandles.end()) {
507  handleIter = _outputHandles.insert(std::pair<std::string, OutputHandle>{detectorName, OutputHandle()}).first;
508  }
509 
510  // Set output facilities
511  handleIter->second.posHitClassName = className;
512 }
513 
514 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
515 
516 void GGSHitsAction::SetHitThreshold(const std::string &detectorName, const std::string &hitType,
517  const std::string &valueStr, const std::string &unit) {
518 
519  const std::string routineName("GGSHitsAction::SetHitThreshold");
520 
521  int hitTypeNo = -1;
522  if (hitType == "integrated") {
523  hitTypeNo = 0;
524  } else if (hitType == "particle") {
525  hitTypeNo = 1;
526  } else if (hitType == "position") {
527  hitTypeNo = 2;
528  } else {
529  throw std::runtime_error(routineName + ": Unknown hit type " + hitType + " for detector " + detectorName);
530  }
531 
532  float value = 0.;
533  try {
534  value = std::stof(valueStr);
535  } catch (std::invalid_argument &exc) {
536  GGSCOUT(ERROR) << "Invalid threshold for " << hitType << " hits of detector " << detectorName << GGSENDL;
537  throw exc;
538  } catch (std::out_of_range &exc) {
539  GGSCOUT(ERROR) << "Invalid value for threshold of " << hitType << " hits of detector " << detectorName << GGSENDL;
540  throw exc;
541  }
542 
543  auto &unitsTable = G4UnitDefinition::GetUnitsTable();
544  auto unitCatIter = std::find_if(unitsTable.begin(), unitsTable.end(),
545  [](const G4UnitsCategory *unitCat) { return (unitCat->GetName() == "Energy"); });
546  if (unitCatIter == unitsTable.end()) {
547  throw std::runtime_error(routineName + ": energy unit category not found");
548  }
549 
550  auto &unitsList = (*unitCatIter)->GetUnitsList();
551  auto unitIter = std::find_if(unitsList.begin(), unitsList.end(), [&unit](const G4UnitDefinition *unitDef) {
552  return unit == unitDef->GetSymbol().c_str();
553  });
554  if (unitIter == unitsList.end()) {
555  throw std::runtime_error(routineName + ": unit " + unit + " not found");
556  }
557 
558  auto thresholdIter = std::find_if(
559  _thresholds.begin(), _thresholds.end(), [&detectorName, hitTypeNo](const ThresholdStruct &threshold) {
560  return (threshold.hitType == hitTypeNo) && (threshold.detectorName == detectorName);
561  });
562  if (thresholdIter == _thresholds.end()) {
563  _thresholds.push_back(ThresholdStruct{detectorName, hitTypeNo, -1.});
564  thresholdIter = _thresholds.end() - 1;
565  }
566 
567  auto *sd =
568  dynamic_cast<GGSIntHitSD *>(G4SDManager::GetSDMpointer()->FindSensitiveDetector(detectorName + ".GGSIntHitSD"));
569  if (!sd) {
570  throw std::invalid_argument(routineName + ": detector " + detectorName + " not found");
571  }
572 
573  switch (hitTypeNo) {
574  case 0:
575  thresholdIter->value = value * (*unitIter)->GetValue();
576  sd->SetIntHitThreshold(thresholdIter->value);
577  break;
578  case 1:
579  thresholdIter->value = value * (*unitIter)->GetValue();
580  sd->SetPartHitThreshold(thresholdIter->value);
581  break;
582  case 2:
583  thresholdIter->value = value * (*unitIter)->GetValue();
584  sd->SetPosHitThreshold(thresholdIter->value);
585  break;
586  }
587 }
588 
589 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
590 
591 GGSHitsAction::GGSHitsActionPrivateMessenger::GGSHitsActionPrivateMessenger(GGSHitsAction *hitsAction)
592  : _hitsAction(hitsAction) {
593  _setThreshCmd = std::make_unique<G4UIcmdWithAString>("/GGS/userActions/hitsAction/setHitThreshold", this);
594  _setThreshCmd->SetGuidance("Set energy deposit threshold for hit output");
595  _setThreshCmd->AvailableForStates(G4State_PreInit, G4State_Idle);
596 }
597 
598 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
599 
600 void GGSHitsAction::GGSHitsActionPrivateMessenger::SetNewValue(G4UIcommand *command, G4String newValue) {
601  const std::string routineName("GGSHitsAction::GGSHitsActionPrivateMessenger::SetNewValue");
602  if (command == _setThreshCmd.get()) {
603  auto tokens = GGSStringUtils::Tokenize(newValue);
604  if (tokens.size() != 4) {
605  throw std::runtime_error(routineName + ": setHitTreshold expects 4 parameters, but " +
606  std::to_string(tokens.size()) + " were given.");
607  }
608 
609  _hitsAction->SetHitThreshold(tokens[0], tokens[1], tokens[2], tokens[3]);
610  }
611 }
612 
613 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
614 
615 void GGSHitsAction::_GiveBackAllArrays() {
616  for (auto &handleElem : _outputHandles) {
617  OutputHandle &handle = handleElem.second;
618  int nIntHits = handle.intHitArray->GetEntries();
619  for (int iIntHit = 0; iIntHit < nIntHits; iIntHit++) {
620  GGSTIntHitBase *intHit = (GGSTIntHitBase *)(handle.intHitArray->At(iIntHit));
621  if (intHit->_partHits) {
622  int nPartHits = intHit->GetNPartHits();
623  for (int iPartHit = 0; iPartHit < nPartHits; iPartHit++) {
624  GGSTPartHitBase *partHit = intHit->GetPartHit(iPartHit);
625  if (partHit->_posHits) {
626  handle.posHitCAService->TakeBackArray(partHit->_posHits);
627  }
628  }
629  handle.partHitCAService->TakeBackArray(intHit->_partHits);
630  }
631  }
632  }
633 }
G4THitsCollection< GGSPosHit > GGSPosHitsCollection
Alias for G4 template hits collection for GGSPosHit.
Definition: GGSPosHit.h:194
OutputMode GetOutputMode()
Gets the ouptut mode.
Sensitive detector class for integrated hits.
Definition: GGSIntHitSD.h:29
A service which manages a pool of reusable TClonesArray.
void EndOfRunAction(const G4Run *run)
Actions executed at end of run.
const std::vector< G4VSensitiveDetector * > & GetListOfSensitiveDetectors()
Retrieves a list of sensitive detectors collected into this object.
int StoreVolume(TFile *tFilePtr, const std::string &detector, const G4VPhysicalVolume *volume, const G4ThreeVector &position, int id)
Set persistence for the specified volume.
void SetHitThreshold(const std::string &detectorName, const std::string &hitType, const std::string &valueStr, const std::string &unit)
Sets a lower energy deposit threshold for hits.
TFile * GetFileForThisRun(const std::filesystem::path &baseName, const G4Run *run)
Opens a file for a given run and returns a pointer to it.
#define GGSENDL
Definition: GGSSmartLog.h:131
GGSTPartHitBase * GetPartHit(unsigned int iHit)
Get the specified particle hit.
Definition: GGSTHits.cpp:182
GGSHitsAction()
Constructor.
~GGSHitsAction()
Destructor.
void CloseFileForThisRun(const std::filesystem::path &baseName, const G4Run *run)
Closes the ROOT output file.
void EndOfEventAction(const G4Event *event)
Actions executed at end of event.
Tokens Tokenize(const std::string &str, char delimiter= ' ')
Extracts words from a string.
bool GetPosHitsStorage()
Return current status of particle hits storage (i.e. persistence).
Definition: GGSIntHitSD.h:142
Definition of GGS Particle Hit.
Definition: GGSPartHit.h:36
Float_t eDep
Total deposited energy.
Definition: GGSTHits.h:41
Definition of GGS Position Hit.
Definition: GGSPosHit.h:33
Base class for storing G4 particle hits.
Definition: GGSTHits.h:106
A multiple sensitive detector.
void BeginOfEventAction(const G4Event *event)
Actions executed at beginning of event.
const std::vector< G4double > & GetTimeBins()
Time bins getter.
Definition: GGSIntHitSD.h:83
void BeginOfRunAction(const G4Run *run)
Actions executed at beginning of run.
bool GetPartHitsStorage()
Return current status of particle hits storage (i.e. persistence).
Definition: GGSIntHitSD.h:117
G4THitsCollection< GGSIntHit > GGSIntHitsCollection
Alias for G4 template hits collection for GGSIntHit.
Definition: GGSIntHit.h:256
void SetOutputPartHitClass(std::string detectorName, const std::string &className)
Sets the name of the particle hit class to be used for output.
TTree * GetDefaultTree(TFile *file)
Gets the default tree for this file.
An action which saves hits in sensitive volumes on ROOT file.
Definition: GGSHitsAction.h:64
static GGSRootFileService & GetInstance()
Get reference to GGSRootFileService unique instance.
Mother class for user actions in GGS.
Definition: GGSUserAction.h:27
Definition of GGS Integrated Hit.
Definition: GGSIntHit.h:32
G4THitsCollection< GGSPartHit > GGSPartHitsCollection
Alias for G4 template hits collection for GGSPartHit.
Definition: GGSPartHit.h:238
void SetOutputPosHitClass(std::string detectorName, const std::string &className)
Sets the name of the position hit class to be used for output.
#define RegisterUA(uaClassName)
Macro for registration of user actions classes.
Base class for storing G4 position hits.
Definition: GGSTHits.h:38
void SetOutputIntHitClass(std::string detectorName, const std::string &className)
Sets the name of the integrated hit class to be used for output of a given detector.
Int_t GetNPartHits()
Gets the number of particle hits.
Definition: GGSTHits.cpp:175
Base class for storing G4 integrated hits.
Definition: GGSTHits.h:218