LDMX Software
AuxInfoReader.cxx
1#include "SimCore/Geo/AuxInfoReader.h"
2
3#include <array>
4
5// LDMX
6#include "Framework/Exception/Exception.h"
11
12// Geant4
13#include "G4FieldManager.hh"
14#include "G4GDMLEvaluator.hh"
15#include "G4LogicalVolumeStore.hh"
16#include "G4ProductionCuts.hh"
17#include "G4ProductionCutsTable.hh"
18#include "G4Region.hh"
19#include "G4RegionStore.hh"
20#include "G4SDManager.hh"
21#include "G4SystemOfUnits.hh"
22#include "G4UniformMagField.hh"
23
24// STL
25#include <cstdlib>
26#include <string>
27
28using std::string;
29
30namespace simcore::geo {
31
32AuxInfoReader::AuxInfoReader(G4GDMLParser* theParser,
34 : parser_(theParser), eval_(new G4GDMLEvaluator) {}
35
40
42 const G4GDMLAuxListType* aux_info_list = parser_->GetAuxList();
43 for (const auto& aux_info : *aux_info_list) {
44 G4String aux_type = aux_info.type;
45 G4String aux_val = aux_info.value;
46
47 if (aux_type == "SensDet") {
48 std::cerr
49 << "[ WARN ] : Not defining SensDet in GDML since v1.0 of SimCore. "
50 "See https://github.com/LDMX-Software/SimCore/issues/39"
51 << std::endl;
52 } else if (aux_type == "MagneticField") {
53 createMagneticField(aux_val, aux_info.auxList);
54 } else if (aux_type == "Region") {
55 createRegion(aux_val, aux_info.auxList);
56 } else if (aux_type == "VisAttributes") {
57 createVisAttributes(aux_val, aux_info.auxList);
58 } else if (aux_type == "DetectorVersion") {
59 createDetectorHeader(aux_val, aux_info.auxList);
60 }
61 }
62 return;
63}
64
66 const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
67 std::vector<G4LogicalVolume*>::const_iterator lvciter;
68 for (lvciter = lvs->begin(); lvciter != lvs->end(); lvciter++) {
69 G4GDMLAuxListType aux_info_list =
70 parser_->GetVolumeAuxiliaryInformation(*lvciter);
71
72 for (const auto& aux_info : aux_info_list) {
73 G4String aux_type = aux_info.type;
74 G4String aux_val = aux_info.value;
75
76 G4LogicalVolume* lv = (*lvciter);
77
78 if (aux_type == "MagneticField") {
79 const G4String& mag_field_name = aux_val;
80 G4MagneticField* mag_field =
82 if (mag_field != nullptr) {
83 auto mgr = new G4FieldManager(mag_field);
84 lv->SetFieldManager(
85 mgr,
86 true /* FIXME: hard-coded to force field manager to daughters */);
87 // G4cout << "Assigned magnetic field " << magFieldName << " to
88 // volume " << lv->GetName() << G4endl;
89 } else {
90 EXCEPTION_RAISE(
91 "MissingInfo",
92 "Unknown MagneticField ref in volume's auxiliary info: " +
93 std::string(mag_field_name.data()));
94 }
95 } else if (aux_type == "Region") {
96 const G4String& region_name = aux_val;
97 G4Region* region = G4RegionStore::GetInstance()->GetRegion(region_name);
98 if (region != nullptr) {
99 region->AddRootLogicalVolume(lv);
100 // G4cout << "Added volume " << lv->GetName() << " to region " <<
101 // regionName << G4endl;
102 } else {
103 EXCEPTION_RAISE("MissingInfo", "Reference region '" +
104 std::string(region_name.data()) +
105 "' was not found!");
106 }
107 } else if (aux_type == "VisAttributes") {
108 const G4String& vis_name = aux_val;
109 G4VisAttributes* vis_attributes =
111 if (vis_attributes != nullptr) {
112 lv->SetVisAttributes(vis_attributes);
113 // G4cout << "Assigned VisAttributes " << visName << " to volume "
114 // << lv->GetName() << G4endl;
115 } else {
116 EXCEPTION_RAISE("MissingInfo", "Referenced VisAttributes '" +
117 std::string(vis_name.data()) +
118 "' was not found!");
119 }
120 }
121 }
122 }
123}
124
125void AuxInfoReader::createMagneticField(const G4String& magFieldName,
126 const G4GDMLAuxListType* auxInfoList) {
127 // Find type of the mag field.
128 G4String mag_field_type("");
129 for (const auto& aux_info : *auxInfoList) {
130 G4String aux_type = aux_info.type;
131 G4String aux_val = aux_info.value;
132
133 if (aux_type == "MagneticFieldType") {
134 mag_field_type = aux_val;
135 break;
136 }
137 }
138
139 if (mag_field_type == "") {
140 EXCEPTION_RAISE("MissingInfo",
141 "Missing MagFieldType for magnetic field definition.");
142 }
143
144 G4MagneticField* mag_field = nullptr;
145
146 // Create a uniform mag field using the built-in Geant4 type.
147 if (mag_field_type == "G4UniformMagField") {
148 double bx, by, bz;
149 bx = by = bz = 0.;
150 for (const auto& aux_info : *auxInfoList) {
151 G4String aux_type = aux_info.type;
152 G4String aux_val = aux_info.value;
153 G4String aux_unit = aux_info.unit;
154
155 G4String expr = aux_val + "*" + aux_unit;
156 if (aux_type == "bx") {
157 bx = eval_->Evaluate(expr);
158 } else if (aux_type == "by") {
159 by = eval_->Evaluate(expr);
160 } else if (aux_type == "bz") {
161 bz = eval_->Evaluate(expr);
162 }
163 }
164 G4ThreeVector field_components(bx, by, bz);
165 mag_field = new G4UniformMagField(field_components);
166
167 // G4cout << "Created G4UniformMagField " << magFieldName << " with field
168 // components " << fieldComponents << G4endl << G4endl;
169
170 // Create a global 3D field map by reading from a data file.
171 } else if (mag_field_type == "MagneticFieldMap3D") {
172 string file_name;
173 double offset_x{};
174 double offset_y{};
175 double offset_z{};
176
177 for (const auto& aux_info : *auxInfoList) {
178 G4String aux_type = aux_info.type;
179 G4String aux_val = aux_info.value;
180 G4String aux_unit = aux_info.unit;
181
182 G4String expr = aux_val + "*" + aux_unit;
183
184 if (aux_type == "File") {
185 file_name = aux_val;
186 } else if (aux_type == "OffsetX") {
187 offset_x = eval_->Evaluate(expr);
188 } else if (aux_type == "OffsetY") {
189 offset_y = eval_->Evaluate(expr);
190 } else if (aux_type == "OffsetZ") {
191 offset_z = eval_->Evaluate(expr);
192 }
193 }
194
195 if (file_name.size() == 0) {
196 EXCEPTION_RAISE("MissingInfo",
197 "File info with field data was not provided.");
198 }
199
200 // Create new 3D field map.
201 mag_field =
202 new MagneticFieldMap3D(file_name.c_str(), offset_x, offset_y, offset_z);
203
204 // Assign field map as global field.
205 G4FieldManager* field_mgr =
206 G4TransportationManager::GetTransportationManager()->GetFieldManager();
207 if (field_mgr->GetDetectorField() != nullptr) {
208 EXCEPTION_RAISE("MisAssign", "Global mag field was already assigned.");
209 }
210 field_mgr->SetDetectorField(mag_field);
211 field_mgr->CreateChordFinder(mag_field);
212
213 } else {
214 EXCEPTION_RAISE("UnknownType", "Unknown MagFieldType '" +
215 std::string(mag_field_type.data()) +
216 "' in auxiliary info.");
217 }
218
219 MagneticFieldStore::getInstance()->addMagneticField(magFieldName, mag_field);
220}
221
222void AuxInfoReader::createRegion(const G4String& name,
223 const G4GDMLAuxListType* auxInfoList) {
224 bool store_trajectories = true;
225 for (const auto& aux_info : *auxInfoList) {
226 G4String aux_type = aux_info.type;
227 G4String aux_val = aux_info.value;
228
229 if (aux_type == "StoreTrajectories") {
230 if (aux_val == "false") {
231 store_trajectories = false;
232 } else if (aux_val == "true") {
233 store_trajectories = true;
234 }
235 }
236 }
237 G4VUserRegionInformation* region_info =
238 new UserRegionInformation(store_trajectories);
239 // This looks like a memory leak, but isn't. I (Einar) have checked. Geant4
240 // registers the region in the constructor and deletes it at the end.
241 //
242 // Some static analysis tools may struggle with identifying that this one
243 // happens to be fine. The NOLINT comment tells clang-tidy to not bother
244 // within the region
245 //
246 // NOLINTBEGIN
247 auto region = new G4Region(name);
248 region->SetUserInformation(region_info);
249 // To get rid of those pesky G4 warnings
250 region->SetProductionCuts(G4ProductionCutsTable::GetProductionCutsTable()
251 ->GetDefaultProductionCuts());
252}
253// NOLINTEND
254
255void AuxInfoReader::createVisAttributes(const G4String& name,
256 const G4GDMLAuxListType* auxInfoList) {
257 std::array<G4double, 4> rgba = {1., 1., 1., 1.};
258 G4bool visible = true;
259 G4bool dau_invisible = false;
260 G4bool force_wireframe = false;
261 G4bool force_solid = false;
262 G4double line_width = 1.0;
263 G4VisAttributes::LineStyle line_style = G4VisAttributes::unbroken;
264
265 for (const auto& aux_info : *auxInfoList) {
266 G4String aux_type = aux_info.type;
267 G4String aux_val = aux_info.value;
268
269 if (aux_type == "R") {
270 rgba[0] = atof(aux_val.c_str());
271 } else if (aux_type == "G") {
272 rgba[1] = atof(aux_val.c_str());
273 } else if (aux_type == "B") {
274 rgba[2] = atof(aux_val.c_str());
275 } else if (aux_type == "A") {
276 rgba[3] = atof(aux_val.c_str());
277 } else if (aux_type == "Style") {
278 if (aux_val == "wireframe") {
279 force_wireframe = true;
280 } else if (aux_val == "solid") {
281 force_solid = true;
282 }
283 } else if (aux_type == "DaughtersInvisible") {
284 if (aux_val == "true") {
285 dau_invisible = true;
286 } else if (aux_val == "false") {
287 dau_invisible = false;
288 }
289 } else if (aux_type == "Visible") {
290 if (aux_val == "true") {
291 visible = true;
292 } else if (aux_val == "false") {
293 visible = false;
294 }
295 } else if (aux_type == "LineStyle") {
296 if (aux_val == "unbroken") {
297 line_style = G4VisAttributes::unbroken;
298 } else if (aux_val == "dashed") {
299 line_style = G4VisAttributes::dashed;
300 } else if (aux_val == "dotted") {
301 line_style = G4VisAttributes::dotted;
302 }
303 } else if (aux_type == "LineWidth") {
304 line_width = atof(aux_val.c_str());
305 }
306 }
307
308 auto vis_attributes = new G4VisAttributes();
309 vis_attributes->SetColor(rgba[0], rgba[1], rgba[2], rgba[3]);
310 vis_attributes->SetVisibility(visible);
311 vis_attributes->SetDaughtersInvisible(dau_invisible);
312 vis_attributes->SetForceWireframe(force_wireframe);
313 vis_attributes->SetForceSolid(force_solid);
314 vis_attributes->SetLineWidth(line_width);
315 vis_attributes->SetLineStyle(line_style);
316 VisAttributesStore::getInstance()->addVisAttributes(name, vis_attributes);
317
318 // G4cout << "Created VisAttributes " << name << G4endl << (*visAttributes) <<
319 // G4endl << G4endl;
320}
321
322void AuxInfoReader::createDetectorHeader(const G4String& auxValue,
323 const G4GDMLAuxListType* auxInfoList) {
324 int detector_version = atoi(auxValue.c_str());
325
326 std::string detector_name("");
327 std::string author("");
328 std::string description("");
329
330 for (const auto& aux_info : *auxInfoList) {
331 G4String aux_type = aux_info.type;
332 G4String aux_val = aux_info.value;
333
334 if (aux_type == "DetectorName") {
335 detector_name = aux_val;
336 } else if (aux_type == "Author") {
337 author = aux_val;
338 } else if (aux_type == "Description") {
339 description = aux_val;
340 }
341 }
342
343 detector_header_ = new ldmx::DetectorHeader(detector_name, detector_version,
344 description, author);
345
346 /*G4cout << G4endl;
347 G4cout << "Read detector header from userinfo: " << G4endl;
348 G4cout << " DetectorName: " << detector_header_->getName() << G4endl;
349 G4cout << " DetectorVersion: " << detector_header_->getVersion() << G4endl;
350 G4cout << " Author: " << detector_header_->getAuthor() << G4endl;
351 G4cout << " Description: " << detector_header_->getDescription() << G4endl;
352 G4cout << G4endl;*/
353}
354} // namespace simcore::geo
Class for defining a global 3D magnetic field.
Class providing a global store to access magnetic field objects.
Class which provides extra information for a detector region.
Class that provides a global visualization attributes store.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
Defines detector header information.
A 3D B-field map defined as a grid of points with associated B-field values.
static MagneticFieldStore * getInstance()
Get the global instance of the magnetic field store.
G4MagneticField * getMagneticField(const std::string &name)
Get a magnetic field by name.
void addMagneticField(const std::string &name, G4MagneticField *magField)
Add a magnetic field by name.
Defines extra information for a detector region.
G4VisAttributes * getVisAttributes(const std::string &name)
Get vis attributes by name.
void addVisAttributes(const std::string &name, G4VisAttributes *visAttributes)
Register a vis attributes by name.
static VisAttributesStore * getInstance()
Get the global instance of the store.
void createDetectorHeader(const G4String &detectorVersion, const G4GDMLAuxListType *auxInfoList)
Create the detector header from the global auxinfo.
virtual ~AuxInfoReader()
Class destructor.
void assignAuxInfoToVolumes()
Assign auxiliary info to volumes such as sensitive detectors.
void readGlobalAuxInfo()
Read the global auxiliary information from the auxinfo block.
AuxInfoReader(G4GDMLParser *parser, const framework::config::Parameters &ps)
Class constructor.
void createVisAttributes(const G4String &name, const G4GDMLAuxListType *auxInfoList)
Create visualization attributes from GDML data.
G4GDMLEvaluator * eval_
The GDML expression evaluator.
G4GDMLParser * parser_
The GDML parser.
ldmx::DetectorHeader * detector_header_
Detector header with name and version.
void createMagneticField(const G4String &name, const G4GDMLAuxListType *auxInfoList)
Create a magnetic field from GDML data.
void createRegion(const G4String &name, const G4GDMLAuxListType *auxInfoList)
Create a detector region from GDML data.