GGS(GenericGEANT4Simulation)Software  2.6.0
 All Data Structures Namespaces Files Functions Variables Typedefs Macros
Data Structures | Public Member Functions | Friends
GGSHitsAction Class Reference

An action which saves hits in sensitive volumes on ROOT file. More...

#include <GGSHitsAction.h>

Inheritance diagram for GGSHitsAction:
Inheritance graph
[legend]
Collaboration diagram for GGSHitsAction:
Collaboration graph
[legend]

Public Member Functions

 GGSHitsAction ()
 Constructor.
 
 ~GGSHitsAction ()
 Destructor.
 
void BeginOfRunAction (const G4Run *run)
 Actions executed at beginning of run. More...
 
void EndOfRunAction (const G4Run *run)
 Actions executed at end of run. More...
 
void BeginOfEventAction (const G4Event *event)
 Actions executed at beginning of event. More...
 
void EndOfEventAction (const G4Event *event)
 Actions executed at end of event. More...
 
void SetOutputFileBase (const std::string &outFileBase)
 Sets the output file base name. More...
 
void SetOutputTreeName (const std::string &outTreeName)
 Sets the output tree name. More...
 
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. More...
 
void SetOutputPartHitClass (std::string detectorName, const std::string &className)
 Sets the name of the particle hit class to be used for output. More...
 
void SetOutputPosHitClass (std::string detectorName, const std::string &className)
 Sets the name of the position hit class to be used for output. More...
 
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. More...
 
- Public Member Functions inherited from GGSUserAction
 GGSUserAction ()
 Constructor. More...
 
virtual ~GGSUserAction ()
 Destructor.
 
G4ClassificationOfNewTrack ClassifyNewTrack (const G4Track *)
 Override of the ClassifyNewTrack method. More...
 

Friends

class GGSHitsActionPrivateMessenger
 

Detailed Description

An action which saves hits in sensitive volumes on ROOT file.

This action reads the hits in sensitive volumes, as defined by GGS sensitive logical volumes naming convention. It then converts the hits in ROOT format and saves them on a ROOT file. For each sensitive logical volume, a branch will be created whose name is equal to that of logical volume. This branch is made by a TClonesArray containing all the hits in physical sensitive volumes associated to the logical. This action can handle different kind of output hit classes derived from standard GGS ones (GGSTIntHit, GGSTPartHit and GGSTPosHit).The actual classes to be used is specified by passing their names to the constructor; the hit classes must have a root dictionary.

See Also
GGSIntHit
GGSPartHit
GGSPosHit

Definition at line 63 of file GGSHitsAction.h.

Member Function Documentation

void GGSHitsAction::BeginOfEventAction ( const G4Event *  event)

Actions executed at beginning of event.

Method executed at the beginning of each event. Hits buffers are cleared.

Parameters
eventPointer to a G4Event

Definition at line 238 of file GGSHitsAction.cpp.

238  {
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 }
void GGSHitsAction::BeginOfRunAction ( const G4Run *  run)

Actions executed at beginning of run.

Method executed at the beginning of each run. A new ROOT file is created for each run.

Parameters
runPointer to the G4Run

Definition at line 67 of file GGSHitsAction.cpp.

67  {
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 }
TFile * GetFileForThisRun(const path &baseName, const G4Run *run)
Opens a file for a given run and returns a pointer to it.
Sensitive detector class for integrated hits.
Definition: GGSIntHitSD.h:28
A service which manages a pool of reusable TClonesArray.
const std::vector< G4VSensitiveDetector * > & GetListOfSensitiveDetectors()
Retrieves a list of sensitive detectors collected into this object.
#define ENDL
Definition: GGSSmartLog.h:93
#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
bool GetPosHitsStorage()
Return current status of particle hits storage (i.e. persistence).
Definition: GGSIntHitSD.h:137
A multiple sensitive detector.
const std::vector< G4double > & GetTimeBins()
Time bins getter.
Definition: GGSIntHitSD.h:83
bool GetPartHitsStorage()
Return current status of particle hits storage (i.e. persistence).
Definition: GGSIntHitSD.h:110
TTree * GetDefaultTree(TFile *file)
Gets the default tree for this file.
static GGSRootFileService & GetInstance()
Get reference to GGSRootFileService unique instance.
void GGSHitsAction::EndOfEventAction ( const G4Event *  event)

Actions executed at end of event.

Method executed at the end of each event. Hits are read, converted to ROOT format and filled into output tree.

Parameters
eventPointer to a G4Event

Definition at line 271 of file GGSHitsAction.cpp.

271  {
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 }
Class to store G4 particle hits.
Definition: GGSTHits.h:82
G4THitsCollection< GGSIntHit > GGSIntHitsCollection
Alias for G4 template hits collection for GGSIntHit.
Definition: GGSIntHit.h:272
Class to store G4 position hits.
Definition: GGSTHits.h:160
void GGSHitsAction::EndOfRunAction ( const G4Run *  run)

Actions executed at end of run.

Method executed at the end of each run. The ROOT tree is written to file and the file is closed.

Parameters
runPointer to a G4Run

Definition at line 199 of file GGSHitsAction.cpp.

199  {
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 }
void CloseFileForThisRun(const path &baseName)
Closes the ROOT output file.
static GGSRootFileService & GetInstance()
Get reference to GGSRootFileService unique instance.
void GGSHitsAction::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.

Hits with a total energy deposit lower than the corresponding threshold will not be saved in the output file. If a finer-grained hit is above its threshold then the parent hit will be saved regardless of its value. For example, if particle hits have threshold 1 and position hits 0.1, then a particle hit with a total release of 0.2 containing a single position hit with release 0.2 will be saved (since position hits are contained inside particle hits, so the particle hit is necessary to store the above-threshold position hit). The energy deposit of parent hits will be the total one computed by the MC simulation, irrespective of the total energy deposit of above-threshold children hits. Extending the example above, if the particle hit have a release of 1.05 due to five position hits with release 0.2 and one position hit with release 0.05 then only the five position hits with release 0.2 will be saved; but the energy deposit of the particle hit will still be 1.05 although the sum of stored position hits is 1. The above consideration apply also to integrated-particle hits hierarchy. In case custom hits are used, which eventually customize the meaning of energy deposit, then the thresholds will be relative to the customized deposits.

Parameters
detectorNameThe name of the detector.
hitTypeThe type of the hit (integrated, particle or position).
valueStrThe threshold value.
unitThe unit of the threshold value.

Definition at line 514 of file GGSHitsAction.cpp.

515  {
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 }
#define ENDL
Definition: GGSSmartLog.h:93
#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 GGSHitsAction::SetOutputFileBase ( const std::string &  outFileBase)
inline

Sets the output file base name.

The file base name can be with or without extension (.root will be automatically used as extension). For each run, the run number will be appended to the base name before the .root extension. If no value is provided the file base name will fallback to the default value set in GSRootFileservice.

Parameters
outFileBaseThe output file base name.
See Also
GGSRootFileservice

Definition at line 117 of file GGSHitsAction.h.

117  {
118  _outFileBase = outFileBase;
119  }
void GGSHitsAction::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.

Parameters
detectorNamename of the detector
classNamename of the output class for integrated hits

Definition at line 448 of file GGSHitsAction.cpp.

448  {
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 }
void GGSHitsAction::SetOutputPartHitClass ( std::string  detectorName,
const std::string &  className 
)

Sets the name of the particle hit class to be used for output.

Parameters
detectorNamename of the detector
classNamename of the output class for particle hits

Definition at line 470 of file GGSHitsAction.cpp.

470  {
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 }
void GGSHitsAction::SetOutputPosHitClass ( std::string  detectorName,
const std::string &  className 
)

Sets the name of the position hit class to be used for output.

Parameters
detectorNamename of the detector
classNamename of the output class for position hits

Definition at line 492 of file GGSHitsAction.cpp.

492  {
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 }
void GGSHitsAction::SetOutputTreeName ( const std::string &  outTreeName)
inline

Sets the output tree name.

This name will be used for the TTree object where th hits for each event will be stored. By default, this value is set to "Hits" in constructor.

Parameters
outTreeNameThe output tree name.

Definition at line 128 of file GGSHitsAction.h.

128  {
129  _outTreeName = outTreeName;
130  }

The documentation for this class was generated from the following files: