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