gdetector
Loading...
Searching...
No Matches
gdetectorConstruction.cc
Go to the documentation of this file.
1// gdetectorConstruction
3#include "gdetector_options.h"
4
5// gemc
9
10// geant4
11#include "G4SDManager.hh"
12#include "G4GeometryManager.hh"
13#include "G4SolidStore.hh"
14#include "G4LogicalVolumeStore.hh"
15#include "G4PhysicalVolumeStore.hh"
16#include "G4ReflectionFactory.hh"
17#include "G4RunManager.hh"
19
20G4ThreadLocal GMagneto* GDetectorConstruction::gmagneto = nullptr;
21
22GDetectorConstruction::GDetectorConstruction(std::shared_ptr<GOptions> gopts)
23 : GBase(gopts, GDETECTOR_LOGGER),
24 G4VUserDetectorConstruction(), // Geant4 base class.
25 gopt(gopts) {
26 // Map is populated after SDs exist, in the SD/field construction path.
27 digitization_routines_map = std::make_shared<gdynamicdigitization::dRoutinesMap>();
28}
29
30// Builds (or rebuilds) the GEMC world and then the Geant4 world.
33
34 // Clean any old geometry.
35 // This is required when reloading geometry, to prevent stale stores and duplicated objects.
36 G4GeometryManager::GetInstance()->OpenGeometry();
37 G4PhysicalVolumeStore::Clean();
38 G4LogicalVolumeStore::Clean();
39 G4SolidStore::Clean();
40 G4ReflectionFactory::Instance()->Clean();
41
42 // Delete old geometry objects if they exist.
43 // These shared_ptr resets guarantee we won't keep references to stale world objects.
44 gworld.reset();
45 g4world.reset();
46
47 // - if no systems are provided, we just launched gemc: create from options
48 // - otherwise, it's a geometry re-load. use existing systems.
49 if (gsystems.empty()) {
50 log->debug(NORMAL, FUNCTION_NAME, "creating world from options");
51 gworld = std::make_shared<GWorld>(gopt);
52 }
53 else {
54 log->debug(NORMAL, FUNCTION_NAME, "creating world from a gsystem vector of size ", gsystems.size());
55 gworld = std::make_shared<GWorld>(gopt, gsystems);
56 }
57
58 // Build Geant4 world (solids, logical and physical volumes) based on the GEMC world.
59 g4world = std::make_shared<G4World>(gworld.get(), gopt);
60
61 auto nsdetectors = gworld->getSensitiveDetectorsList().size();
62
63 // tally with number :
64 log->info(0, "Tally summary: \n - ", gworld->get_number_of_volumes() - 1, " volumes\n - ",
65 g4world->number_of_volumes(), " geant4 built volumes\n - ",
66 nsdetectors, " sensitive detectors\n");
67
68
69 // Return the physical volume for the ROOT world volume.
71}
72
73// Installs sensitive detectors and EM fields for the constructed geometry.
75 auto sdManager = G4SDManager::GetSDMpointer();
76
78
79 // Local cache of sensitive detectors keyed by digitization name.
80 // Multiple volumes can share the same digitization name and therefore reuse one SD instance.
81 std::unordered_map<std::string, GSensitiveDetector*> sensitiveDetectorsMap;
82
83 // Loop over all systems and their volumes.
84 for (const auto& [systemName, gsystemPtr] : *gworld->getSystemsMap()) {
85 for (const auto& [volumeName, gvolumePtr] : gsystemPtr->getGVolumesMap()) {
86 auto const& digitizationName = gvolumePtr->getDigitization();
87 auto const& g4name = gvolumePtr->getG4Name();
88 auto* g4volume = g4world->getG4Volume(g4name)->getLogical();
89
90 // Ensure the Geant4 logical volume exists.
91 // Some GEMC volumes can be "copy-of" another volume; in that case, reuse the
92 // referenced Geant4 logical volume rather than failing.
93 if (g4volume == nullptr) {
94 std::string copyOf = gvolumePtr->getCopyOf();
95 if (copyOf != "" && copyOf != UNINITIALIZEDSTRINGQUANTITY) {
96 auto gsystem = gvolumePtr->getSystem();
97 auto volume_copy = gsystem + "/" + copyOf;
98 auto copyG4Volume = g4world->getG4Volume(volume_copy)->getLogical();
99 if (copyG4Volume != nullptr) { g4volume = copyG4Volume; }
100 else {
101 log->error(ERR_GVOLUMENOTFOUND, FUNCTION_NAME, " Logical volume copy <" + volume_copy + "> not found.");
102 }
103 }
104 }
105 if (g4volume == nullptr) {
106 log->error(ERR_GVOLUMENOTFOUND, FUNCTION_NAME, " Logical volume <" + g4name + "> not found.");
107 }
108
109
110 // Skip volumes with no digitization.
111 if (digitizationName != "" && digitizationName != UNINITIALIZEDSTRINGQUANTITY) {
112 // Create the sensitive detector if it does not exist yet.
113 if (sensitiveDetectorsMap.find(digitizationName) == sensitiveDetectorsMap.end()) {
114 log->info(2, "Creating new sensitive detector <", digitizationName, "> for volume <", g4name, ">");
115
116 sensitiveDetectorsMap[digitizationName] = new GSensitiveDetector(digitizationName, gopt);
117 }
118 else { log->info(2, "Sensitive detector <", digitizationName, "> is already created and available for volume <", g4name, ">"); }
119
120 // Register the volume touchable with the sensitive detector.
121 // The touchable encodes identity and dimension metadata needed by digitization.
122 const auto& vdimensions = gvolumePtr->getDetectorDimensions();
123 const auto& identity = gvolumePtr->getGIdentity();
124 auto this_gtouchable = std::make_shared<GTouchable>(gopt, digitizationName, identity, vdimensions);
125 sensitiveDetectorsMap[digitizationName]->registerGVolumeTouchable(g4name, this_gtouchable);
126
127 // Register the detector with Geant4 and attach it to the logical volume.
128 sdManager->AddNewDetector(sensitiveDetectorsMap[digitizationName]);
129 g4volume->SetSensitiveDetector(sensitiveDetectorsMap[digitizationName]);
130 log->info(2, "Logical Volume <" + g4name + "> has been successfully assigned to SD.", sensitiveDetectorsMap[digitizationName]);
131 }
132
133 // Process electromagnetic fields.
134 // If a volume declares an EM field, ensure the field container exists and install
135 // a per-volume field manager configured by the named field map.
136 const auto& field_name = gvolumePtr->getEMField();
137 if (field_name != "" && field_name != UNINITIALIZEDSTRINGQUANTITY) {
138 if (gmagneto == nullptr) { gmagneto = new GMagneto(gopt); }
139 log->info(2, "Volume <", volumeName, "> has field: <", field_name, ">. Looking into field map definitions.");
140 log->info(2, "Setting field manager for volume <", g4name, "> with field <", field_name, ">");
141 g4world->setFieldManagerForVolume(g4name, gmagneto->getFieldMgr(field_name).get(), true);
142 }
143 }
144 }
145
146 // Load digitization plugins after constructing sensitive detectors.
147 // This populates digitization_routines_map for each sensitive detector name.
148 loadDigitizationPlugins();
149
150 // Bind each digitization routine to its corresponding sensitive detector.
151 const auto sdetectors = gworld->getSensitiveDetectorsList();
152 for (auto& sdname : sdetectors) {
153 sensitiveDetectorsMap[sdname]->assign_digi_routine(digitization_routines_map->at(sdname));
154 log->info(1, "Digitization routine <" + sdname + "> has been successfully assigned to SD.", sensitiveDetectorsMap[sdname]);
155 }
156}
157
158// Loads (or dynamically resolves) the digitization routine for each sensitive detector.
159void GDetectorConstruction::loadDigitizationPlugins() {
160 const auto sdetectors = gworld->getSensitiveDetectorsList();
161
162 for (auto& sdname : sdetectors) {
163 if (sdname == FLUXNAME) {
164 log->info(1, "Loading flux digitization plugin for routine <" + sdname + ">");
165 digitization_routines_map->emplace(sdname, std::make_shared<GFluxDigitization>(gopt));
166 }
167 else if (sdname == COUNTERNAME) {
168 log->info(1, "Loading particle counter digitization plugin for routine <" + sdname + ">");
169 digitization_routines_map->emplace(sdname, std::make_shared<GParticleCounterDigitization>(gopt));
170 }
171 else if (sdname == DOSIMETERNAME) {
172 log->info(1, "Loading dosimeter digitization plugin for routine <" + sdname + ">");
173 digitization_routines_map->emplace(sdname, std::make_shared<GDosimeterDigitization>(gopt));
174 }
175 else {
176 // if it's not in the map already, add it
177 log->info(0, "Loading new digitization plugin for routine <" + sdname + ">");
178 digitization_routines_map->emplace(sdname, gdynamicdigitization::load_dynamicRoutine(sdname, gopt));
179 }
180
181 // Ensure each routine uses the correct logger and is configured for readout.
182 digitization_routines_map->at(sdname)->set_loggers(gopt);
183
184 if (digitization_routines_map->at(sdname)->defineReadoutSpecs()) { log->info(1, "Digitization routine <" + sdname + "> has been successfully defined."); }
185 else { log->error(ERR_DEFINESPECFAIL, "defineReadoutSpecs failure for <" + sdname + ">"); }
186 }
187}
188
189
191 // it could be empty for tests
192 if (!sl.empty()) {
193 // Use vector assignment to update the local systems.
194 gsystems = sl;
195 }
196
197 // Reconstruct the geometry and update the world volume - if the run manager exists
198 auto rm = G4RunManager::GetRunManager();
199
200 // TODO: not sure if DefineWorldVolume also call ConstructSDandField automatically?
201 // is this all there is to do here to reload a geometry?
202 if (rm) {
203 rm->DefineWorldVolume(Construct());
205 }
206 else { log->error(1, "GDetectorConstruction::reload_geometry", "Geant4 Run manager not found."); }
207}
G4VPhysicalVolume * getPhysical() const noexcept
G4LogicalVolume * getLogical() const noexcept
std::size_t number_of_volumes() const noexcept
void setFieldManagerForVolume(const std::string &volumeName, G4FieldManager *fm, bool forceToAllDaughters)
const G4Volume * getG4Volume(const std::string &volumeName) const
std::shared_ptr< GLogger > log
GDetectorConstruction(std::shared_ptr< GOptions > gopts)
Constructs a detector builder configured by the provided options.
void reload_geometry(SystemList sl)
Reloads the geometry using a new list of GSystem objects.
G4VPhysicalVolume * Construct() override
Geant4 geometry construction hook.
void ConstructSDandField() override
Geant4 SD/field construction hook.
void debug(debug_type type, Args &&... args) const
void info(int level, Args &&... args) const
void error(int exit_code, Args &&... args) const
std::shared_ptr< G4FieldManager > getFieldMgr(std::string name)
int get_number_of_volumes() const
std::vector< std::string > getSensitiveDetectorsList()
SystemMap * getSystemsMap() const
Defines the GDetectorConstruction class, the Geant4 detector-construction entry point for the gdetect...
Declares the gdetector module option aggregation entry point.
constexpr const char * GDETECTOR_LOGGER
Logger name used by the gdetector module.
#define FUNCTION_NAME
NORMAL
#define ERR_GVOLUMENOTFOUND
#define ROOTWORLDGVOLUMENAME
std::vector< SystemPtr > SystemList
#define UNINITIALIZEDSTRINGQUANTITY
std::shared_ptr< GDynamicDigitization > load_dynamicRoutine(const std::string &plugin_name, const std::shared_ptr< GOptions > &gopts)