GGS(GenericGEANT4Simulation)Software  2.99.0
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Macros
GGSDetectorConstruction.cpp
Go to the documentation of this file.
1 /*
2  * GGSDetectorConstruction.cpp
3  *
4  * Created on: 2010-09-29
5  * Authors: Emiliano Mocchiutti and Cecilia Pizzolotto
6  */
7 
10 // Geant4 headers
11 #include "G4GeometryManager.hh"
12 #include "G4LogicalVolumeStore.hh"
13 #include "G4PhysicalVolumeStore.hh"
14 #include "G4SDManager.hh"
15 #include "G4SolidStore.hh"
16 #include "G4UIcmdWithAString.hh"
17 #include "G4UImanager.hh"
18 #ifdef USE_GDML
19 #include "G4GDMLParser.hh"
20 #endif
21 
22 // DD4HEP headers
23 #ifdef GGS_USE_DD4HEP
24 #include "DD4hep/Detector.h"
25 #include "DDG4/Geant4Converter.h"
26 #include "DDG4/Geant4DetectorConstruction.h"
27 #endif
28 
29 // GGS headers
35 #include "utils/GGSNameDecoder.h"
36 #include "utils/GGSSmartLog.h"
37 
38 // C++ headers
39 #include <stdexcept>
40 
41 namespace {
42 // Messenger for build commands for sensitive detectors
43 class SDBuildMessenger : public G4UImessenger {
44 public:
45  SDBuildMessenger(const G4String &path, const G4String &dsc);
46  void AddSDBuildCommand(const std::string &newCommand);
47  void SetNewValue(G4UIcommand *command, G4String newValue);
48  void BuildSD(const std::string &sdClassName, const std::string &logVolNameAndParams);
49 
50 private:
51  std::vector<G4UIcmdWithAString> _sdBuildCommands;
52 };
53 
54 G4ThreadLocal std::unique_ptr<SDBuildMessenger> sdBuildMessenger = nullptr;
55 
56 SDBuildMessenger::SDBuildMessenger(const G4String &path, const G4String &dsc) : G4UImessenger(path, dsc) {}
57 
58 void SDBuildMessenger::AddSDBuildCommand(const std::string &newCommand) {
59  _sdBuildCommands.emplace_back(newCommand.c_str(), this);
60 }
61 
62 void SDBuildMessenger::SetNewValue(G4UIcommand *command, G4String newValue) {
63  std::string path = command->GetCommandPath();
64  if (path.size() > 16 && path.substr(0, 16) == "/GGS/scoring/add") {
65  // Build user actions
66  auto sdClassName = path.substr(16);
67  BuildSD(sdClassName, newValue);
68  }
69 }
70 
71 void SDBuildMessenger::BuildSD(const std::string &sdClassName, const std::string &logVolNameAndParams) {
72  static const std::string routineName("GGSScoringManager::AddSDToLogVol");
73 
74  // Attach the sensitive detector to all the logical volumes
75  G4String logVolName = logVolNameAndParams.substr(0, logVolNameAndParams.find_first_of(' '));
76  auto separatorPos = logVolNameAndParams.find_first_of(' ');
77  G4String params;
78  if (separatorPos != std::string::npos) {
79  params = logVolNameAndParams.substr(logVolNameAndParams.find_first_of(' ') + 1);
80  }
81 
82  auto AddSDToLogVol = [](G4VSensitiveDetector *sd, G4LogicalVolume *logVol) {
83  // Add sd to logical volume
84  if (logVol->GetSensitiveDetector() == nullptr) {
85  // Case 1: logical has not a sd. Add the newly built sd to it
86  logVol->SetSensitiveDetector(sd);
87  } else {
88  GGSMultiSensitiveDetector *multiSD = dynamic_cast<GGSMultiSensitiveDetector *>(logVol->GetSensitiveDetector());
89  if (multiSD) {
90  // Case 2: the current sd is a multisd. Add the newly built sd to it
91  multiSD->AddSensitiveDetector(sd);
92  } else {
93  // Case 3: the current sd is a standard sd. Replace it with a multisd and add it and the newly built sd to
94  // the multisd
95  multiSD = new GGSMultiSensitiveDetector(G4String(logVol->GetName()).append(".GGSMultiSD"));
96  multiSD->AddSensitiveDetector(logVol->GetSensitiveDetector());
97  multiSD->AddSensitiveDetector(sd);
98  G4SDManager::GetSDMpointer()->AddNewDetector(multiSD);
99  logVol->SetSensitiveDetector(multiSD);
100  }
101  }
102 
103  // Add the sd to the sdmanager if it has not already been added
104  if (G4SDManager::GetSDMpointer()->GetHCtable()->GetCollectionID(sd->GetName()) == -1) {
105  G4SDManager::GetSDMpointer()->AddNewDetector(sd);
106  }
107  };
108 
109  G4LogicalVolumeStore::const_iterator logVol = G4LogicalVolumeStore::GetInstance()->begin();
110  G4VSensitiveDetector *sd = nullptr;
111  for (; logVol != G4LogicalVolumeStore::GetInstance()->end(); ++logVol) {
112  if ((*logVol)->GetName() == logVolName) {
113  if (!sd) {
114  // Build the sd
115  G4String sdName = sdClassName;
116  if (params != "") {
117  sdName.append(".").append(params);
118  }
119 
121  .CreateObject(sdClassName, logVolName + '.' + sdName)
122  .release();
123  if (!sd) {
124  G4ExceptionDescription ed;
125  ed << "No registered builder for sensitive detector " << sdClassName << std::endl;
126  G4Exception("GGSUserActionInitialization::UAIMessenger::SetNewValue", "Invalid generator",
127  G4ExceptionSeverity::FatalException, ed);
128  }
129  }
130  // Add sd to logvol
131  if (G4Threading::IsMultithreadedApplication() && G4Threading::IsMasterThread()) {
132  // Add the sd to the sdmanager if it has not already been added
133  if (G4SDManager::GetSDMpointer()->GetHCtable()->GetCollectionID(sd->GetName()) == -1) {
134  G4SDManager::GetSDMpointer()->AddNewDetector(sd);
135  }
136  } else {
137  AddSDToLogVol(sd, *logVol);
138  }
139  }
140  }
141 
142  if (!sd) {
143  G4ExceptionDescription ed;
144  ed << routineName << ": logical volume " << logVolName << " not present. Sensitive detector " << sdClassName
145  << " not added." << std::endl;
146  G4Exception("GGSUserActionInitialization::UAIMessenger::SetNewValue", "Invalid generator",
147  G4ExceptionSeverity::FatalException, ed);
148  }
149 }
150 
151 } // namespace
152 
153 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
154 
155 GGSDetectorConstruction::GGSDetectorConstruction(const G4String &library, const G4String &configDataCard)
156  : _physicalWorld(nullptr), _geometry(nullptr), _library(library), _configDataCard(configDataCard), _gdxml(""),
157  _messenger(this, "/GGS/"), _nToPrintForVectGeoParams{10} {
158  _messenger.DeclareProperty("nToPrintForVectGeoParams", _nToPrintForVectGeoParams,
159  "Maximum number of elemts to print for vector parameters (default: 10; 0 -> all)");
160 }
161 
162 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
163 
164 GGSDetectorConstruction::GGSDetectorConstruction(const G4String &library, const G4String &,
165  const G4String &configDataCard, bool)
166  : _physicalWorld(nullptr), _geometry(nullptr), _library(library), _configDataCard(configDataCard), _gdxml(""),
167  _messenger(this, "/GGS/"), _nToPrintForVectGeoParams{10} {
168  _messenger.DeclareProperty("nToPrintForVectGeoParams", _nToPrintForVectGeoParams,
169  "Maximum number of elemts to print for vector parameters (default: 10; 0 -> all)");
170 }
171 
172 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
173 
175  : _physicalWorld(nullptr), _geometry(nullptr), _library(""), _configDataCard(""), _gdxml(gdxml),
176  _messenger(this, "/GGS/"), _nToPrintForVectGeoParams{10} {
177  _messenger.DeclareProperty("nToPrintForVectGeoParams", _nToPrintForVectGeoParams,
178  "Maximum number of elemts to print for vector parameters (default: 10; 0 -> all)");
179 }
180 
181 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
182 
184 
185 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
186 
187 namespace {
188 #ifdef USE_GDML
189 // Geometry construction class for top-level GDML file.
190 // This class provides a thin and feature-less geometry construction to be used when
191 // a GDML file is used instead of a geometry library.
192 class GGSGDMLGeometryConstruction : public GGSVGeometryConstruction {
193 public:
194  // The world parameter must be a pointer to the already constructed world volume.
195  GGSGDMLGeometryConstruction(G4VPhysicalVolume *world) : _world(world) {}
196  G4VPhysicalVolume *Construct() { return _world; }
197  G4VPhysicalVolume *GetVolume() { return _world; };
198 
199 private:
200  G4VPhysicalVolume *_world;
201 };
202 #endif
203 
204 #ifdef GGS_USE_DD4HEP
205 // Geometry construction class for DD4hep geometries.
206 // This class provides a thin and feature-less geometry construction to be used when
207 // a DD4hep geometry is used instead of a geometry library.
208 class GGSDD4hepGeometryConstruction : public GGSVGeometryConstruction {
209 public:
210  // The world parameter must be a pointer to the already constructed world volume.
211  GGSDD4hepGeometryConstruction(G4VPhysicalVolume *world) : _world(world) {}
212  G4VPhysicalVolume *Construct() { return _world; }
213  G4VPhysicalVolume *GetVolume() { return _world; };
214 
215 private:
216  G4VPhysicalVolume *_world;
217 };
218 #endif
219 
220 template <typename T> void PrintVectParams(const T &paramsVect, size_t nToPrint) {
221  for (auto &par : paramsVect) {
222  GGSCCOUT(INFO) << par.first << ": {";
223  for (size_t iVal = 0; iVal < std::min(par.second.size() - 1, nToPrint - 1); ++iVal) {
224  GGSCOUT_BACKEND << par.second[iVal] << ", ";
225  }
226  if (nToPrint != 0 && par.second.size() > nToPrint) {
227  GGSCOUT_BACKEND << "..., ";
228  }
229  GGSCOUT_BACKEND << par.second.back() << "}\n";
230  }
231 }
232 
233 } // namespace
234 
236 
237  static const std::string routineName("GGSDetectorConstruction::Construct");
238 
239  // 1. Construct the geometry
240  if (_library != "") {
241  // 1.1 Load the concrete GGSVGeometryConstruction from a shared library
242  if (!(GGSGeoPluginManager::GetInstance().LoadGeoPlugin(_library))) {
243  GGSCOUT(ERROR) << "Impossible to load geometry library " << _library << GGSENDL;
244  throw std::runtime_error("Impossible to load geometry library");
245  }
247  if (!_geometry) {
248  GGSCOUT(ERROR) << "Can't create the geometry." << GGSENDL;
249  }
250  GGSCOUT(INFO) << "Construct the detector." << GGSENDL;
251  _geometry->SetGeoDataCard(_configDataCard);
252  _physicalWorld = _geometry->Construct();
253  // Print geometry version
254  const std::string geoVersion = _geometry->GetVersion();
255  if (geoVersion != "") {
256  GGSCOUT(INFO) << "Geometry version: " << geoVersion << GGSENDL;
257  } else {
258  GGSCOUT(INFO) << "No geometry version available" << GGSENDL;
259  }
260  // Print geometry parameters
261  _geometry->ExportParameters(); // Will throw if something goes wrong, so don't check the return value
262  auto intParams = _geometry->GetIntParameters();
263  auto boolParams = _geometry->GetBoolParameters();
264  auto realParams = _geometry->GetRealParameters();
265  auto stringParams = _geometry->GetStringParameters();
266  auto vectIntParams = _geometry->GetVectIntParameters();
267  auto vectBoolParams = _geometry->GetVectBoolParameters();
268  auto vectRealParams = _geometry->GetVectRealParameters();
269  auto vectStringParams = _geometry->GetVectStringParameters();
270  if (intParams.size() != 0 || boolParams.size() != 0 || realParams.size() != 0 || stringParams.size() != 0 ||
271  vectIntParams.size() != 0 || vectBoolParams.size() != 0 || vectRealParams.size() != 0 ||
272  vectStringParams.size() != 0) {
273  GGSCOUT(INFO) << "Geometry parameters:\n";
274  for (auto &par : intParams) {
275  GGSCCOUT(INFO) << par.first << ": " << par.second << "\n";
276  }
277  for (auto &par : boolParams) {
278  GGSCCOUT(INFO) << par.first << ": " << (par.second ? "true" : "false") << "\n";
279  }
280  for (auto &par : realParams) {
281  GGSCCOUT(INFO) << par.first << ": " << par.second << "\n";
282  }
283  for (auto &par : stringParams) {
284  GGSCCOUT(INFO) << par.first << ": " << par.second << "\n";
285  }
286  PrintVectParams(vectIntParams, _nToPrintForVectGeoParams);
287  PrintVectParams(vectRealParams, _nToPrintForVectGeoParams);
288  PrintVectParams(vectBoolParams, _nToPrintForVectGeoParams);
289  PrintVectParams(vectStringParams, _nToPrintForVectGeoParams);
290  }
291  }
292 #ifdef USE_GDML
293  else if (_gdxml.length() > 4 && _gdxml.substr(_gdxml.length() - 5) == ".gdml") {
294  // 1.2 Build the geometry from a GDML file
295  G4GDMLParser gdmlParser;
296  gdmlParser.SetOverlapCheck(false);
297  try {
298  gdmlParser.Read(_gdxml, false);
299  } catch (int &ge) {
300  GGSCOUT(ERROR) << "G4GDML: " << ge << ", missing network connection? wrong schema URL?" << GGSENDL;
301  // G4GGSCOUT << "Try to read GDML file _WITHOUT_ schema validation" << G4GGSENDL;
302  // error, try without schema validation
303  // gdmlParser.ValidateSchema(false);
304  // gdmlParser.Read(_gdxml, false);
305  }
306  gdmlParser.StripNamePointers();
307  _physicalWorld = gdmlParser.GetWorldVolume();
308  if (!_physicalWorld) {
309  GGSCOUT(ERROR) << "Cannot build the GMDL geometry." << GGSENDL;
310  throw std::runtime_error("Cannot build the GMDL geometry.");
311  }
312  _geometry = new GGSGDMLGeometryConstruction(_physicalWorld);
313  }
314 #endif
315 #ifdef GGS_USE_DD4HEP
316  else if (_gdxml.length() > 3 && _gdxml.substr(_gdxml.length() - 4) == ".xml") {
317  // 1.3 Build the DD4hep geometry
318  dd4hep::Detector &detDesc = dd4hep::Detector::getInstance();
319  detDesc.fromXML(_gdxml);
320  dd4hep::DetElement world = detDesc.world();
321  dd4hep::sim::Geant4Converter conv(detDesc, dd4hep::NOLOG);
322  dd4hep::sim::Geant4GeometryInfo *geoInfo = conv.create(world).detach();
323  _physicalWorld = geoInfo->world();
324  _geometry = new GGSDD4hepGeometryConstruction(_physicalWorld);
325  }
326 #endif
327 
328  // 2. Construct the standard SDs
329  // This feature is removed from GGS, so print an error message and throw an exception.
330 
331  const G4LogicalVolumeStore *logicalVolumeStore = G4LogicalVolumeStore::GetInstance();
332  std::vector<G4LogicalVolume *>::const_iterator i;
334  for (i = logicalVolumeStore->begin(); i != logicalVolumeStore->end(); i++) {
335  std::string logVolName = (*i)->GetName();
336  auto detVolName = logVolName.substr(0, logVolName.find_first_of(' '));
337  auto spacePos = logVolName.find_last_of(' ');
338  std::string scorerName("");
339  if (spacePos != std::string::npos)
340  scorerName = logVolName.substr(spacePos + 1);
341  // check if it is a sensitive volume
342  if (nameDecoder.IsSensitive(detVolName)) {
343  GGSCOUT(WARNING) << "This version of GGS does not support the definition of sensitive volumes by name ("
344  << detVolName << ").\n";
345  GGSCCOUT(WARNING) << "Please change the name of the volume and make it active using a datacard command."
346  << GGSENDL;
347  throw std::runtime_error("Use of removed feature: definition of sensitive volume by name.");
348  }
349  }
350 
351  return _physicalWorld;
352 }
353 
354 void GGSDetectorConstruction::ConstructSDandField() {
355  // Construct the build commands for the sensitive detectors
356  sdBuildMessenger = std::make_unique<SDBuildMessenger>("/GGS/scoring/", "Messenger for SD build commands");
357  auto &availableSDBuilders =
359  for (auto &builder : availableSDBuilders) {
360  // Create the command
361  sdBuildMessenger->AddSDBuildCommand("/GGS/scoring/add" + builder);
362  }
363 }
364 
365 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#define GGSCCOUT(level)
Smart log utility which prints no header at the beginning of the line.
Definition: GGSSmartLog.h:126
GGSDetectorConstruction(const G4String &library, const G4String &configDataCard)
Constructor.
const std::map< std::string, std::vector< bool > > & GetVectBoolParameters()
Getter method for vector-of-booleans geometry parameters.
#define GGSCOUT_BACKEND
Smart log macro. It writes on stdout only if the specified verbosity level is lesser than the maximum...
Definition: GGSSmartLog.h:100
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.
Abstract class needed to load GGS geometry.
static GGSGeoPluginManager & GetInstance()
Get the singleton instance.
G4VPhysicalVolume * Construct()
Override of the Construct method.
#define GGSENDL
Definition: GGSSmartLog.h:131
const std::map< std::string, std::vector< std::string > > & GetVectStringParameters()
Getter method for vector-of-strings geometry parameters.
std::unique_ptr< T > CreateObject(const std::string &name, ConstructorArgs...arguments)
Create an object.
Definition: GGSFactory.h:116
const std::vector< std::string > & GetListOfRegisteredBuilders()
Gets a vector containing the names of available registered builders.
Definition: GGSFactory.h:111
virtual G4VPhysicalVolume * Construct()=0
Construct the detector - virtual method.
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.
A multiple sensitive detector.
const std::map< std::string, std::vector< double > > & GetVectRealParameters()
Getter method for vector-of-reals geometry parameters.
virtual const std::string GetVersion()
Getter method for geometry version.
const std::map< std::string, bool > & GetBoolParameters()
Getter method for boolean geometry parameters.
virtual bool ExportParameters()
Function for exporting the geometry parameters.
static GGSFactory & GetInstance()
Getter method for singleton pointer.
Definition: GGSFactory.h:72
GGSVGeometryConstruction * GetGeoConstruction()
Returns the geometry construction object.
static GGSNameDecoder & GetInstance()
Get instance of the singleton.
virtual G4VPhysicalVolume * GetVolume()=0
Get the detector VPhysicalVolume - virtual method.
bool IsSensitive(const std::string &volumeName)
Check if the logical volume is sensitive.
void AddSensitiveDetector(G4VSensitiveDetector *sd)
Adds a new sensitive detector to the multidetector.
Class needed to decode sensitive volume names.
void SetGeoDataCard(const G4String &dataCard)
Sets the geometry configuration datacard.