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