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