GGS(GenericGEANT4Simulation)Software  2.99.0
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Macros
Data Structures | Public Types | Public Member Functions | Static Public Member Functions | Friends
GGSRootFileService Class Reference

Singleton for a centralized ROOT files management. More...

#include <GGSRootFileService.h>

Public Types

enum  OutputMode { SINGLEFILE, MULTIFILE }
 Aliases for the different output modes. More...
 

Public Member Functions

TFile * GetFileForThisRun (const std::filesystem::path &baseName, const G4Run *run)
 Opens a file for a given run and returns a pointer to it. More...
 
void CloseFileForThisRun (const std::filesystem::path &baseName, const G4Run *run)
 Closes the ROOT output file. More...
 
TTree * GetDefaultTree (TFile *file)
 Gets the default tree for this file. More...
 
void SetSuffix (const std::string &suffix)
 Sets the suffix for file names. More...
 
void SetDefaultFileBase (const std::filesystem::path &newFileBase)
 Sets the default file name. More...
 
int StoreVolume (TFile *tFilePtr, const std::string &detector, const G4VPhysicalVolume *volume, const G4ThreeVector &position, int id)
 Set persistence for the specified volume. More...
 
void SetSimInfo (const GGSTSimInfo &simInfo)
 Set the simulation info object to be saved on output files. More...
 
OutputMode GetOutputMode ()
 Gets the ouptut mode. More...
 

Static Public Member Functions

static GGSRootFileServiceGetInstance ()
 Get reference to GGSRootFileService unique instance. More...
 

Friends

class GGSMultiUserAction
 
struct std::hash< VolumeKey >
 

Detailed Description

Singleton for a centralized ROOT files management.

The aim of this class is to provide a centralized management for ROOT output files. For each run, the singleton will provide pointers to output file to the action which may require them with the GetFileForThisRun method. The purpose of this is to allow multiple actions to write on the same ROOT file, avoiding the proliferation of output files when many actions are in use. Typically, the singleton will create a file the first time that file is requested; if subsequently other actions require the same file, the singleton will not open it again, but it will simply return a pointer to the already opened file. Consistently, file closure requests issued by calling CloseFileForThisRun will be ignored until no more actions require that file. Users wishing to use this service in their actions are demanded to call GetFileForThisRun in BeginOfRunAction to get the file and to close it with CloseFileForThisRun in EndOfRunAction. The service also provides a standard TTree called GGSEventsTree to let actions save their event data in different branches of the same tree rather than in different trees. This helps I/O performance. See GetDefaultTree.

Definition at line 46 of file GGSRootFileService.h.

Member Enumeration Documentation

Aliases for the different output modes.

In MT mode, the output can be either on a single Root file or in one Root file per thread. These two possibilities are encoded in this enum class.

Definition at line 154 of file GGSRootFileService.h.

154 { SINGLEFILE, MULTIFILE };

Member Function Documentation

void GGSRootFileService::CloseFileForThisRun ( const std::filesystem::path &  baseName,
const G4Run *  run 
)

Closes the ROOT output file.

The closure request is handled this way: if a file has been requested N times, it will be closed when this method is called for the N-th time. This will avoid to close the file when other actions may still need it.

WARNING: when a ROOT file is closed, all the TTree objects associated to it will be automatically deleted. User must NOT delete its trees before calling this method. Eg.:

outRootFile->cd(); outTree->Write(); GGSRootFileService::GetInstance().CloseFileForThisRun(outBase); //delete outTree; // Uncommenting this will generate a segfault

Parameters
baseNameThe file base name.
runThe current run.

Definition at line 167 of file GGSRootFileService.cpp.

167  {
168 
169  G4AutoLock lock(mutexForCloseFile);
170 
171  std::filesystem::path absPath;
172 
173  // Set default if no base name has been provided
174  if (baseName.string() == "") {
175  absPath = _defaultOutBase;
176  } else
177  absPath = baseName;
178  // Retrieve absolute path
179  absPath = _GetAbsolutePath(absPath);
180 
181  // Strip extension and append suffix and extension
182  absPath = _AppendSuffixAndExt(absPath, run);
183 
184  // Helper lambda that writes the general simulation information on the output file
185  auto WriteGeneralSimInfo = [this](TFile *outFile) {
186  // Write simulation informations
187  outFile->WriteObjectAny(&_simInfo, "GGSTSimInfo", _simInfo.GetName());
188 
189  // Write geometry informations
191  GGSTGeoParams geoParams;
192  geoParams.SetIntGeoParams(geoCons->GetIntParameters());
193  geoParams.SetBoolGeoParams(geoCons->GetBoolParameters());
194  geoParams.SetRealGeoParams(geoCons->GetRealParameters());
195  geoParams.SetStringGeoParams(geoCons->GetStringParameters());
196  geoParams.SetVectIntGeoParams(geoCons->GetVectIntParameters());
197  geoParams.SetVectBoolGeoParams(geoCons->GetVectBoolParameters());
198  geoParams.SetVectRealGeoParams(geoCons->GetVectRealParameters());
199  geoParams.SetVectStringGeoParams(geoCons->GetVectStringParameters());
200  outFile->WriteObject(&geoParams, "GGSGeoParams");
201 
202  // Write generator informations
203  // These are written only for GGS generators that export a parameter object containing the "generator" name
204  // setting.
205  auto *genAction =
206  dynamic_cast<const GGSGeneratorAction *>(GGSRunManager::GetRunManager()->GetUserPrimaryGeneratorAction());
207  if (genAction) {
208  GGSTParameters generatorParams(genAction->GetParameters());
209  try {
210  generatorParams.GetParam<std::string>("generator"); // Throws if "generator" parameter is not present
211  outFile->WriteObject(&generatorParams, "GGSGenParams");
212  } catch (...) {
213  }
214  }
215  };
216 
217  int iThread = G4Threading::G4GetThreadId();
218  for (auto fileInfoIter = _filesInfo.begin(); fileInfoIter != _filesInfo.end(); ++fileInfoIter) {
219  if (fileInfoIter->absPath == absPath) {
220  for (auto tFileInfoIter = fileInfoIter->tFilesInfo.begin(); tFileInfoIter != fileInfoIter->tFilesInfo.end();
221  ++tFileInfoIter) {
222  if (tFileInfoIter->threadNo == iThread) {
223  --(tFileInfoIter->nRequests);
224  if (tFileInfoIter->nRequests == 0) {
225  if (tFileInfoIter->defaultEventsTree) {
226  tFileInfoIter->defaultEventsTree->Write(); // The tree is already associated to the right TFile
227  }
228  // Write the detectors array and the general simulation information in the file, but if there is a buffer
229  // merger then do it later just on the merged file
230  if (!(fileInfoIter->bufferMerger)) {
231  if (fileInfoIter->detectorsArray) {
232  tFileInfoIter->tFile->WriteObject(fileInfoIter->detectorsArray, "GGSHitDetInfo", "SingleKey");
233  }
234  WriteGeneralSimInfo(tFileInfoIter->tFile.get());
235  }
236  // Mute due to this:
237  // https://root-forum.cern.ch/t/warning-message-when-merging-files-with-tbuffermerger/42349
238  // WARNING: this will suppress any output message from other threads occurring at the same time.
239  GGSSmartLog::MuteOutput();
240  tFileInfoIter->tFile->Write();
241  GGSSmartLog::UnmuteOutput();
242  tFileInfoIter = --(fileInfoIter->tFilesInfo.erase(tFileInfoIter));
243  } else {
244  return;
245  }
246  }
247  }
248  if (fileInfoIter->tFilesInfo.size() == 0) {
249  if (fileInfoIter->bufferMerger) {
250  // Delete the buffer merger
251  fileInfoIter->bufferMerger.reset();
252  // Open the file for writing global objects
253  auto outFile = std::unique_ptr<TFile>(TFile::Open(fileInfoIter->absPath.string().c_str(), "UPDATE"));
254  if (fileInfoIter->detectorsArray) {
255  outFile->WriteObject(fileInfoIter->detectorsArray, "GGSHitDetInfo", "SingleKey");
256  }
257  WriteGeneralSimInfo(outFile.get());
258  outFile->Close();
259  }
260  fileInfoIter = --(_filesInfo.erase(fileInfoIter));
261  }
262  }
263  }
264 }
const std::map< std::string, std::vector< bool > > & GetVectBoolParameters()
Getter method for vector-of-booleans geometry parameters.
void SetVectBoolGeoParams(const std::map< std::string, std::vector< bool >> &vectBoolGeoParams)
Sets the vector-of-booleans geometry parameters.
const std::map< std::string, int > & GetIntParameters()
Getter method for integer geometry parameters.
const std::map< std::string, double > & GetRealParameters()
Getter method for real geometry parameters.
Base class for GGS generator actions.
Abstract class needed to load GGS geometry.
static GGSGeoPluginManager & GetInstance()
Get the singleton instance.
T GetParam(const std::string &name) const
Gets a parameter.
void SetStringGeoParams(const std::map< std::string, std::string > &stringGeoParams)
Sets the string geometry parameters.
const std::map< std::string, std::vector< std::string > > & GetVectStringParameters()
Getter method for vector-of-strings geometry parameters.
void SetRealGeoParams(const std::map< std::string, double > &realGeoParams)
Sets the real geometry parameters.
const std::map< std::string, std::vector< int > > & GetVectIntParameters()
Getter method for vector-of-integers geometry parameters.
const std::map< std::string, std::string > & GetStringParameters()
Getter method for string geometry parameters.
const std::map< std::string, std::vector< double > > & GetVectRealParameters()
Getter method for vector-of-reals geometry parameters.
void SetVectRealGeoParams(const std::map< std::string, std::vector< double >> &vectRealGeoParams)
Sets the vector-of-reals geometry parameters.
void SetVectStringGeoParams(const std::map< std::string, std::vector< std::string >> &vectStringGeoParams)
Sets the vector-of-strings geometry parameters.
const std::map< std::string, bool > & GetBoolParameters()
Getter method for boolean geometry parameters.
Class for storing the geometry parameters on Root output file.
Definition: GGSTGeoParams.h:18
void SetVectIntGeoParams(const std::map< std::string, std::vector< int >> &vectIntGeoParams)
Sets the vector-of-integers geometry parameters.
GGSVGeometryConstruction * GetGeoConstruction()
Returns the geometry construction object.
void SetBoolGeoParams(const std::map< std::string, bool > &boolGeoParams)
Sets the boolean geometry parameters.
Class for writing parameters into the output Root file.
void SetIntGeoParams(const std::map< std::string, int > &intGeoParams)
Sets the integer geometry parameters.
TTree * GGSRootFileService::GetDefaultTree ( TFile *  file)

Gets the default tree for this file.

This method returns the default events tree for the specified file. This is intended to allow user actions to write their output as branches of the same tree instead of using a tree for each action. In this way the best performance of the I/O system of ROOT can be exploited (see https://twiki.cern.ch/twiki/bin/view/LHCb/PersistencyMigration#POOL). The Fill() and Write() operations for the default tree are managed by GGSRootFileService. The only operation that can be done with the tree is the creation of a branch. Explicitly calling Fill() or Write() for the default tree in user actions will result in a wrong number of events and in multiple keys for the tree in the output file. Fill() will be automatically called at the end of each event after calling EndOfEventAction() for every user action.

Different default trees can be requested for different files.

Parameters
fileThe file on which the default tree will be saved. This file pointer must have been previously retrieved by calling GetFileForThisRun; DON'T use a file created in any other way.
Returns
a pointer to the default tree, NULL if file has not been created by GetFileForThisRun.

Definition at line 266 of file GGSRootFileService.cpp.

266  {
267  // Don't allow other threads to ask for a file in the meantime since this might invalidate the references in the
268  // loops
269  G4AutoLock lock(mutexForGetFile);
270 
271  for (auto &fileInfo : _filesInfo) {
272  for (auto &tFileInfo : fileInfo.tFilesInfo) {
273  if (file == tFileInfo.tFile.get()) {
274  if (tFileInfo.defaultEventsTree == nullptr) {
275  tFileInfo.defaultEventsTree = new TTree("GGSEventsTree", "GGS events tree. Info: ", 99, file);
276  }
277  return tFileInfo.defaultEventsTree;
278  }
279  }
280  }
281  return nullptr;
282 }
TFile * GGSRootFileService::GetFileForThisRun ( const std::filesystem::path &  baseName,
const G4Run *  run 
)

Opens a file for a given run and returns a pointer to it.

This method will open a file for a given run and return a pointer to it; if the file is already opened, it will simply return the pointer without attempting to open it again. The created file will be named baseName.root for run 0 (eventually baseName_suffix.root if a suffix is specified calling SetSuffix); for subsequent runs, it will be named baseName_RunID.root (or baseName_RunID_suffix.root).

Parameters
baseNameThe file base name (.root extension, run ID and suffix will be (eventually) automatically appended). If an empty name is provided, the default one ("GGSRootOutput") will be used (the default name can be set with SetDefaultFileBase).
runThe current run.
Returns
Pointer to the output ROOT file.

Definition at line 85 of file GGSRootFileService.cpp.

85  {
86 
87  G4AutoLock lock(mutexForGetFile);
88 
89  std::filesystem::path absPath;
90 
91  // Set default if no base name has been provided
92  if (baseName.string() == "") {
93  absPath = _defaultOutBase;
94  } else {
95  absPath = baseName;
96  }
97 
98  // Retrieve absolute path
99  absPath = _GetAbsolutePath(absPath);
100 
101  // Strip extension and append suffix and extension
102  absPath = _AppendSuffixAndExt(absPath, run);
103 
104  // Lambda that creates a new TFile for current thread and for the given file info
105  auto CreateNewTFile = [this, &absPath](FileInfoContainer::iterator fileInfoIter) -> TFile * {
106  std::shared_ptr<TFile> newTFile = nullptr;
107  if (G4Threading::IsMultithreadedApplication() && _singleFileForMT) {
108  // Create the TFile with TBufferMerger in MT single-file mode
109  if (!fileInfoIter->bufferMerger) {
110  fileInfoIter->bufferMerger = std::make_unique<ROOT::TBufferMerger>(absPath.string().c_str());
111  }
112  newTFile = fileInfoIter->bufferMerger->GetFile();
113  } else {
114  // Create the TFile normally in ST mode or in MT multi-file mode
115  if (fileInfoIter->tFilesInfo.size() != 0) {
116  G4Exception("GGSRootFileService::GetFileForThisRun", "TFile clash", G4ExceptionSeverity::FatalException,
117  ("A TFile is already existing for file " + absPath.string() + " in ST mode; can't create it again")
118  .c_str());
119  }
120  newTFile = std::make_shared<TFile>(absPath.string().c_str(), "RECREATE");
121  }
122  fileInfoIter->tFilesInfo.emplace_back();
123  auto &tFileInfo = fileInfoIter->tFilesInfo.back();
124  tFileInfo.tFile = newTFile;
125  tFileInfo.defaultEventsTree = nullptr;
126  tFileInfo.threadNo = G4Threading::G4GetThreadId();
127  tFileInfo.nRequests = 1;
128 
129  return newTFile.get();
130  };
131 
132  // Check if the file info is already present
133  int iThread = G4Threading::G4GetThreadId();
134  auto fileInfoIter = _filesInfo.begin();
135  for (; fileInfoIter != _filesInfo.end(); ++fileInfoIter) {
136  if (absPath == fileInfoIter->absPath) {
137  // File info found. Check for the TFile
138  for (auto &tFileInfo : fileInfoIter->tFilesInfo) {
139  if (tFileInfo.threadNo == iThread) {
140  ++(tFileInfo.nRequests);
141  return tFileInfo.tFile.get();
142  }
143  }
144  // TFile not found. Create and return it
145  return CreateNewTFile(fileInfoIter);
146  }
147  }
148 
149  // File info has not been found, so create it
150  _filesInfo.emplace_back();
151  fileInfoIter = --(_filesInfo.end());
152  fileInfoIter->absPath = absPath;
153 
154  // Create the TFile
155  TFile *newTFile = CreateNewTFile(fileInfoIter);
156 
157  // Set storage of detector to nullptr values to force proper initialization in StoreVolume
158  _currVolStorageTFile = nullptr;
159  _currDetVolName = "";
160 
161  return newTFile;
162 }
GGSRootFileService & GGSRootFileService::GetInstance ( )
static

Get reference to GGSRootFileService unique instance.

Returns
reference to the root file service.

Definition at line 71 of file GGSRootFileService.cpp.

71  {
72  static GGSRootFileService instance;
73  return instance;
74 }
Singleton for a centralized ROOT files management.
OutputMode GGSRootFileService::GetOutputMode ( )
inline

Gets the ouptut mode.

In MT mode, this method will return OutputMode::SINGLEFILE if the simulation output of the different threads will be merged into a single output file, or OutputMode::MULTIFILE if there will be one output file per thread. In ST mode it always returns OutputMode::SINGLEFILE.

Returns
The output mode (single-file or multi-file).

Definition at line 164 of file GGSRootFileService.h.

164 { return (_singleFileForMT ? OutputMode::SINGLEFILE : OutputMode::MULTIFILE); }
void GGSRootFileService::SetDefaultFileBase ( const std::filesystem::path &  newFileBase)
inline

Sets the default file name.

The default file name is used when a file is requested by calling GetFileForThisRun but no file name is provided.

Parameters
newFileBaseThe new default file base name (optionally with boost::filesystem::path).

Definition at line 122 of file GGSRootFileService.h.

122 { _defaultOutBase = newFileBase; }
void GGSRootFileService::SetSimInfo ( const GGSTSimInfo simInfo)
inline

Set the simulation info object to be saved on output files.

Parameters
simInfoThe object containing informations about the simulation.

Definition at line 147 of file GGSRootFileService.h.

147 { _simInfo = simInfo; }
void GGSRootFileService::SetSuffix ( const std::string &  suffix)
inline

Sets the suffix for file names.

The suffix will be appended after just before the .root extension.

Parameters
suffixThe suffix.

Definition at line 114 of file GGSRootFileService.h.

114 { _suffix = suffix; }
int GGSRootFileService::StoreVolume ( TFile *  tFilePtr,
const std::string &  detector,
const G4VPhysicalVolume *  volume,
const G4ThreeVector &  position,
int  id 
)

Set persistence for the specified volume.

The specified volume (volume name, position and id) will be saved as a GGSTHitVolInfo object inside the GGSTHitDetInfo object corresponding to the specified detector. The GGSTHitDetInfo is saved as an element of a TClonesArray called GGSHitDetArray inside the specified file.

The (volume name, id) pair must be unique for each volume to be stored.

Parameters
tFilePtrThe TFile where to save the informations about detectors and volumes.
detectorThe name of the detector.
volumeThe pointer to the physical volume.
positionThe position of the volume (in internal G4 units; will be saved in [cm]).
idThe ID of the volume (see GGSTHitVolInfo).
Returns
The position of the volume in the store.
See Also
GGSTHitVolInfo

Definition at line 345 of file GGSRootFileService.cpp.

346  {
347  static const std::string routineName("GGSRootFileService::StoreVolume");
348 
349  G4AutoLock lock(mutexForStoreVolume);
350  std::string detVolName = detector.substr(0, detector.find_first_of('.'));
351 
352  // 1. Retrieve file info structure
353  bool fileChanged = false, found = false;
354  if (tFilePtr != _currVolStorageTFile) {
355  fileChanged = true;
356  _currVolStorageTFile = tFilePtr;
357 
358  for (_currVolStorageFileInfo = _filesInfo.begin(); _currVolStorageFileInfo != _filesInfo.end();
359  ++_currVolStorageFileInfo) {
360  for (auto &tFileInfo : _currVolStorageFileInfo->tFilesInfo) {
361  if (tFileInfo.tFile.get() == tFilePtr) {
362  found = true;
363  break;
364  }
365  }
366  if (found) {
367  break;
368  }
369  }
370  if (!found) {
371  G4Exception("GGSRootFileService::StoreVolume", "TFile not found", G4ExceptionSeverity::FatalException,
372  (std::string("TFile for ") + tFilePtr->GetName() + " is not managed by GGSRootFileService").c_str());
373  }
374  }
375 
376  // 2. Find the detector in the index
377  if (fileChanged || _currDetVolName != detVolName) {
378  _currDetVolName = detVolName;
379  int currPersDetectorIndex = 0;
380  for (_currDetector = _currVolStorageFileInfo->detectorsMap.begin();
381  _currDetector != _currVolStorageFileInfo->detectorsMap.end(); ++_currDetector, ++currPersDetectorIndex) {
382  if (_currDetector->first == _currDetVolName) {
383  break;
384  }
385  }
386  if (_currDetector == _currVolStorageFileInfo->detectorsMap.end()) {
387  // 2.1 Detector not found. Create it both in index and persistence array
388  _currVolStorageFileInfo->detectorsMap.push_back(
389  std::make_pair<std::string, HitVolMap>(std::string(_currDetVolName), HitVolMap()));
390  _currDetector = _currVolStorageFileInfo->detectorsMap.end(); // Past-the-end iterator
391  --_currDetector; // Set the iterator to the last element
392  if (_currVolStorageFileInfo->detectorsArray == nullptr) {
393  _currVolStorageFileInfo->detectorsArray = new TClonesArray("GGSTHitDetInfo");
394  }
395  currPersDetectorIndex = _currVolStorageFileInfo->detectorsArray->GetEntries(); // Redundant
396  _currPersDetector = new ((*(_currVolStorageFileInfo->detectorsArray))[currPersDetectorIndex]) GGSTHitDetInfo;
397  _currPersDetector->detectorName = _currDetVolName.data();
398  } else {
399  // 2.2 Detector found. Set the current persistent detector
400  _currPersDetector = (GGSTHitDetInfo *)(_currVolStorageFileInfo->detectorsArray->At(currPersDetectorIndex));
401  }
402  }
403 
404  // 3. Insert the volume in the index and in the persistency structure
405 
406  // Append volume ID to volume name to avoid placing all the replicated volumes at the same place in the index
407  std::string volAndId = volume->GetName() + std::to_string(id);
408 
409  auto insertResult =
410  _currDetector->second.emplace(VolumeKey(volAndId, volume, position), _currPersDetector->volumes.GetEntries());
411  if (insertResult.second) {
412  // 3.1 No hash collision: this is a new volume. Add it also to the volumes array in detector object...
413  GGSTHitVolInfo *volInfo =
414  new ((_currPersDetector->volumes)[_currPersDetector->volumes.GetEntries()]) GGSTHitVolInfo;
415  volInfo->volumeName = volume->GetName().data();
416  for (int i = 0; i < 3; i++) {
417  volInfo->volumePos[i] = position[i] / cm;
418  }
419  volInfo->id = id;
420  // ... then return its position in the array
421  return _currPersDetector->volumes.GetEntries() - 1;
422  } else {
423  // 3.2 A hash collision has happened: the volume is already present. So take its position from the index
424  return insertResult.first->second;
425  }
426 }
Float_t volumePos[3]
Position of the touchable in world volume coordinates [cm].
Int_t id
ID of the volume.
Class to store detector informations.
TClonesArray volumes
Array of GGSTHitVolInfo objects.
TString volumeName
Name of the physical volume.
GGSTHitVolInfo.h GGSTHitVolInfo class declaration.
TString detectorName
Name of detector associated to integrated hits.

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