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 }
56 else {
57 log->debug(NORMAL, FUNCTION_NAME, "creating world from a gsystem vector of size ", gsystems.size());
58 gworld = std::make_shared<GWorld>(gopt, gsystems);
59 }
60
61 // Build Geant4 world (solids, logical and physical volumes) based on the GEMC world.
62 g4world = std::make_shared<G4World>(gworld.get(), gopt);
63
64 auto nsdetectors = gworld->getSensitiveDetectorsList().size();
65
66 // tally with number :
67 log->info(0, "Tally summary: \n - ", gworld->get_number_of_volumes() - 1, " volumes\n - ",
68 g4world->number_of_volumes(), " geant4 built volumes\n - ",
69 nsdetectors, " sensitive detectors\n");
70
71
72 // Return the physical volume for the ROOT world volume.
74}
75
76// Installs sensitive detectors and EM fields for the constructed geometry.
78 auto sdManager = G4SDManager::GetSDMpointer();
79
81
82 // Local cache of sensitive detectors keyed by digitization name.
83 // Multiple volumes can share the same digitization name and therefore reuse one SD instance.
84 std::unordered_map<std::string, GSensitiveDetector*> sensitiveDetectorsMap;
85
86 // Loop over all systems and their volumes.
87 for (const auto& [systemName, gsystemPtr] : *gworld->getSystemsMap()) {
88 for (const auto& [volumeName, gvolumePtr] : gsystemPtr->getGVolumesMap()) {
89 auto const& digitizationName = gvolumePtr->getDigitization();
90 auto const& g4name = gvolumePtr->getG4Name();
91 auto* g4volume = g4world->getG4Volume(g4name)->getLogical();
92
93 // Ensure the Geant4 logical volume exists.
94 // Some GEMC volumes can be "copy-of" another volume; in that case, reuse the
95 // referenced Geant4 logical volume rather than failing.
96 if (g4volume == nullptr) {
97 std::string copyOf = gvolumePtr->getCopyOf();
98 if (copyOf != "" && copyOf != UNINITIALIZEDSTRINGQUANTITY) {
99 auto gsystem = gvolumePtr->getSystem();
100 auto volume_copy = gsystem + "/" + copyOf;
101 auto copyG4Volume = g4world->getG4Volume(volume_copy)->getLogical();
102 if (copyG4Volume != nullptr) { g4volume = copyG4Volume; }
103 else {
105 " Logical volume copy <" + volume_copy + "> not found.");
106 }
107 }
108 }
109 if (g4volume == nullptr) {
110 log->error(ERR_GVOLUMENOTFOUND, FUNCTION_NAME, " Logical volume <" + g4name + "> not found.");
111 }
112
113 // Skip volumes with no digitization.
114 if (digitizationName != "" && digitizationName != UNINITIALIZEDSTRINGQUANTITY) {
115 // Create the sensitive detector if it does not exist yet.
116 if (sensitiveDetectorsMap.find(digitizationName) == sensitiveDetectorsMap.end()) {
117 log->info(2, "Creating new sensitive detector <", digitizationName, "> for volume <", g4name, ">");
118
119 sensitiveDetectorsMap[digitizationName] = new GSensitiveDetector(digitizationName, gopt);
120 }
121 else {
122 log->info(2, "Sensitive detector <", digitizationName,
123 "> is already created and available for volume <", g4name, ">");
124 }
125
126 // Register the volume touchable with the sensitive detector.
127 // The touchable encodes identity and dimension metadata needed by digitization.
128 const auto& vdimensions = gvolumePtr->getDetectorDimensions();
129 const auto& identity = gvolumePtr->getGIdentity();
130 const auto& mass = g4volume->GetMass();
131 auto this_gtouchable = std::make_shared<
132 GTouchable>(gopt, digitizationName, identity, vdimensions, mass);
133 sensitiveDetectorsMap[digitizationName]->registerGVolumeTouchable(g4name, this_gtouchable);
134
135 // Register the detector with Geant4 and attach it to the logical volume.
136 sdManager->AddNewDetector(sensitiveDetectorsMap[digitizationName]);
137 g4volume->SetSensitiveDetector(sensitiveDetectorsMap[digitizationName]);
138
139 // auto maxStep =
140
141 //g4volume->SetUserLimits(new G4UserLimits(0.1*mm, 0.1*mm));
142
143 log->info(2, "Logical Volume <" + g4name + "> has been successfully assigned to SD.",
144 sensitiveDetectorsMap[digitizationName]);
145 }
146
147 // Process electromagnetic fields.
148 // If a volume declares an EM field, ensure the field container exists and install
149 // a per-volume field manager configured by the named field map.
150 const auto& field_name = gvolumePtr->getEMField();
151 if (field_name != "" && field_name != UNINITIALIZEDSTRINGQUANTITY) {
152 if (gmagneto == nullptr) { gmagneto = new GMagneto(gopt); }
153 log->info(2, "Volume <", volumeName, "> has field: <", field_name,
154 ">. Looking into field map definitions.");
155 log->info(2, "Setting field manager for volume <", g4name, "> with field <", field_name, ">");
156 g4world->setFieldManagerForVolume(g4name, gmagneto->getFieldMgr(field_name).get(), true);
157 }
158 }
159 }
160
161 // Load digitization plugins after constructing sensitive detectors.
162 // This populates digitization_routines_map for each sensitive detector name.
163 loadDigitizationPlugins();
164
165 // Bind each digitization routine to its corresponding sensitive detector.
166 const auto sdetectors = gworld->getSensitiveDetectorsList();
167 for (auto& sdname : sdetectors) {
168 auto digitization_routine = digitization_routines_map->at(sdname);
169 double maxStep = digitization_routine->readoutSpecs->getMaxStep();
170
171 sensitiveDetectorsMap[sdname]->assign_digi_routine(digitization_routine);
172 log->info(1, "Digitization routine <" + sdname + "> has been successfully assigned to SD.",
173 sensitiveDetectorsMap[sdname]);
174
175 // Loop over all systems and their volumes.
176 // and assign max step to the corresponding logical volume
177 for (const auto& [systemName, gsystemPtr] : *gworld->getSystemsMap()) {
178 for (const auto& [volumeName, gvolumePtr] : gsystemPtr->getGVolumesMap()) {
179 auto const& digitizationName = gvolumePtr->getDigitization();
180 if (digitizationName == sdname) {
181 auto const& g4name = gvolumePtr->getG4Name();
182 auto* g4volume = g4world->getG4Volume(g4name)->getLogical();
183
184 // g4volume->SetUserLimits(new G4UserLimits(maxStep, maxStep)); // this will also kill track cause
185 // the second argument is max track length
186 g4volume->SetUserLimits(new G4UserLimits(maxStep));
187
188 log->info(1, "Setting G4UserLimits for volume <", g4name, "> with maxStep <", maxStep, ">");
189 }
190 }
191 }
192
193 }
194}
195
196// Loads (or dynamically resolves) the digitization routine for each sensitive detector.
197void GDetectorConstruction::loadDigitizationPlugins() {
198 const auto sdetectors = gworld->getSensitiveDetectorsList();
199
200 for (auto& sdname : sdetectors) {
201 if (sdname == FLUXNAME) {
202 log->info(1, "Loading flux digitization plugin for routine <" + sdname + ">");
203 digitization_routines_map->emplace(sdname, std::make_shared<GFluxDigitization>(gopt));
204 }
205 else if (sdname == COUNTERNAME) {
206 log->info(1, "Loading particle counter digitization plugin for routine <" + sdname + ">");
207 digitization_routines_map->emplace(sdname, std::make_shared<GParticleCounterDigitization>(gopt));
208 }
209 else if (sdname == DOSIMETERNAME) {
210 log->info(1, "Loading dosimeter digitization plugin for routine <" + sdname + ">");
211 digitization_routines_map->emplace(sdname, std::make_shared<GDosimeterDigitization>(gopt));
212 }
213 else {
214 // if it's not in the map already, add it
215 log->info(0, "Loading new digitization plugin for routine <" + sdname + ">");
216 digitization_routines_map->emplace(sdname, gdynamicdigitization::load_dynamicRoutine(sdname, gopt));
217 }
218
219 // Ensure each routine uses the correct logger and is configured for readout.
220 digitization_routines_map->at(sdname)->set_loggers(gopt);
221
222 if (digitization_routines_map->at(sdname)->defineReadoutSpecs()) {
223 log->info(1, "Digitization routine <" + sdname + "> has been successfully defined.");
224 }
225 else { log->error(ERR_DEFINESPECFAIL, "defineReadoutSpecs failure for <" + sdname + ">"); }
226 }
227}
228
229
231 // it could be empty for tests
232 if (!sl.empty()) {
233 // Use vector assignment to update the local systems.
234 gsystems = sl;
235 }
236
237 // Reconstruct the geometry and update the world volume - if the run manager exists
238 auto rm = G4RunManager::GetRunManager();
239
240 // TODO: not sure if DefineWorldVolume also call ConstructSDandField automatically?
241 // is this all there is to do here to reload a geometry?
242 if (rm) {
243 rm->DefineWorldVolume(Construct());
245 }
246 else { log->error(1, "GDetectorConstruction::reload_geometry", "Geant4 Run manager not found."); }
247}
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)