LDMX Software
simcore::geo::AuxInfoReader Class Reference

Reads auxiliary information from GDML userinfo block. More...

#include <AuxInfoReader.h>

Public Member Functions

 AuxInfoReader (G4GDMLParser *parser, const framework::config::Parameters &ps)
 Class constructor.
 
virtual ~AuxInfoReader ()
 Class destructor.
 
void readGlobalAuxInfo ()
 Read the global auxiliary information from the auxinfo block.
 
void assignAuxInfoToVolumes ()
 Assign auxiliary info to volumes such as sensitive detectors.
 
ldmx::DetectorHeadergetDetectorHeader ()
 Get the detector header that was created from the userinfo block.
 

Private Member Functions

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.
 
void selectColorMode (const G4String &mode)
 Select the 'mode' for coloring in the visualization.
 
void createVisAttributes (const G4String &name, const G4GDMLAuxListType *auxInfoList)
 Create visualization attributes from GDML data.
 
void createDetectorHeader (const G4String &detectorVersion, const G4GDMLAuxListType *auxInfoList)
 Create the detector header from the global auxinfo.
 

Private Attributes

G4GDMLParser * parser_
 The GDML parser.
 
G4GDMLEvaluator * eval_
 The GDML expression evaluator.
 
ldmx::DetectorHeaderdetector_header_ {nullptr}
 Detector header with name and version.
 
std::string color_mode_
 Color mode for visattributes.
 
std::vector< std::string > universal_visattributes_
 

Detailed Description

Reads auxiliary information from GDML userinfo block.

Note
This class reads information to define a detector header block, sensitive detectors, visualization attributes, magnetic fields, detector IDs, and detector regions from the userinfo block of a GDML file. These objects are then assigned to the appropriate logical volumes which have auxiliary tags that reference these objects by name.

Definition at line 28 of file AuxInfoReader.h.

Constructor & Destructor Documentation

◆ AuxInfoReader()

simcore::geo::AuxInfoReader::AuxInfoReader ( G4GDMLParser * parser,
const framework::config::Parameters & ps )

Class constructor.

Parameters
parserThe GDML parser.
psconfiguration parameters

Definition at line 32 of file AuxInfoReader.cxx.

34 : parser_(theParser), eval_(new G4GDMLEvaluator) {}
G4GDMLEvaluator * eval_
The GDML expression evaluator.
G4GDMLParser * parser_
The GDML parser.

◆ ~AuxInfoReader()

simcore::geo::AuxInfoReader::~AuxInfoReader ( )
virtual

Class destructor.

Definition at line 36 of file AuxInfoReader.cxx.

36 {
37 delete eval_;
38 delete detector_header_;
39}
ldmx::DetectorHeader * detector_header_
Detector header with name and version.

References detector_header_, and eval_.

Member Function Documentation

◆ assignAuxInfoToVolumes()

void simcore::geo::AuxInfoReader::assignAuxInfoToVolumes ( )

Assign auxiliary info to volumes such as sensitive detectors.

Definition at line 67 of file AuxInfoReader.cxx.

67 {
68 const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
69 std::vector<G4LogicalVolume*>::const_iterator lvciter;
70 for (lvciter = lvs->begin(); lvciter != lvs->end(); lvciter++) {
71 G4GDMLAuxListType aux_info_list =
72 parser_->GetVolumeAuxiliaryInformation(*lvciter);
73
74 for (const auto& aux_info : aux_info_list) {
75 G4String aux_type = aux_info.type;
76 G4String aux_val = aux_info.value;
77
78 G4LogicalVolume* lv = (*lvciter);
79
80 if (aux_type == "MagneticField") {
81 const G4String& mag_field_name = aux_val;
82 G4MagneticField* mag_field =
84 if (mag_field != nullptr) {
85 auto mgr = new G4FieldManager(mag_field);
86 lv->SetFieldManager(
87 mgr,
88 true /* FIXME: hard-coded to force field manager to daughters */);
89 // G4cout << "Assigned magnetic field " << magFieldName << " to
90 // volume " << lv->GetName() << G4endl;
91 } else {
92 EXCEPTION_RAISE(
93 "MissingInfo",
94 "Unknown MagneticField ref in volume's auxiliary info: " +
95 std::string(mag_field_name.data()));
96 }
97 } else if (aux_type == "Region") {
98 const G4String& region_name = aux_val;
99 G4Region* region = G4RegionStore::GetInstance()->GetRegion(region_name);
100 if (region != nullptr) {
101 region->AddRootLogicalVolume(lv);
102 // G4cout << "Added volume " << lv->GetName() << " to region " <<
103 // regionName << G4endl;
104 } else {
105 EXCEPTION_RAISE("MissingInfo", "Reference region '" +
106 std::string(region_name.data()) +
107 "' was not found!");
108 }
109 } else if (aux_type == "VisAttributes") {
110 // Same as when registering visattributes, must match mode (if in use)
111 auto match = std::find(universal_visattributes_.begin(),
112 universal_visattributes_.end(), aux_val);
113 if (match == universal_visattributes_.end() && color_mode_ != "" &&
114 aux_val.find(color_mode_) == std::string::npos) {
115 continue;
116 }
117 const G4String& vis_name = aux_val;
118 G4VisAttributes* vis_attributes =
120 if (vis_attributes != nullptr) {
121 lv->SetVisAttributes(vis_attributes);
122 // G4cout << "Assigned VisAttributes " << visName << " to volume "
123 // << lv->GetName() << G4endl;
124 } else {
125 EXCEPTION_RAISE("MissingInfo", "Referenced VisAttributes '" +
126 std::string(vis_name.data()) +
127 "' was not found!");
128 }
129 }
130 }
131 }
132}
static MagneticFieldStore * getInstance()
Get the global instance of the magnetic field store.
G4MagneticField * getMagneticField(const std::string &name)
Get a magnetic field by name.
G4VisAttributes * getVisAttributes(const std::string &name)
Get vis attributes by name.
static VisAttributesStore * getInstance()
Get the global instance of the store.
std::string color_mode_
Color mode for visattributes.

References color_mode_, simcore::MagneticFieldStore::getInstance(), simcore::VisAttributesStore::getInstance(), simcore::MagneticFieldStore::getMagneticField(), simcore::VisAttributesStore::getVisAttributes(), and parser_.

◆ createDetectorHeader()

void simcore::geo::AuxInfoReader::createDetectorHeader ( const G4String & detectorVersion,
const G4GDMLAuxListType * auxInfoList )
private

Create the detector header from the global auxinfo.

Parameters
detectorVersionThe aux value with the detector version.
auxInfoListThe aux info with the detector header information.

Definition at line 376 of file AuxInfoReader.cxx.

377 {
378 int detector_version = atoi(auxValue.c_str());
379
380 std::string detector_name("");
381 std::string author("");
382 std::string description("");
383
384 for (const auto& aux_info : *auxInfoList) {
385 G4String aux_type = aux_info.type;
386 G4String aux_val = aux_info.value;
387
388 if (aux_type == "DetectorName") {
389 detector_name = aux_val;
390 } else if (aux_type == "Author") {
391 author = aux_val;
392 } else if (aux_type == "Description") {
393 description = aux_val;
394 }
395 }
396
397 detector_header_ = new ldmx::DetectorHeader(detector_name, detector_version,
398 description, author);
399
400 /*G4cout << G4endl;
401 G4cout << "Read detector header from userinfo: " << G4endl;
402 G4cout << " DetectorName: " << detector_header_->getName() << G4endl;
403 G4cout << " DetectorVersion: " << detector_header_->getVersion() << G4endl;
404 G4cout << " Author: " << detector_header_->getAuthor() << G4endl;
405 G4cout << " Description: " << detector_header_->getDescription() << G4endl;
406 G4cout << G4endl;*/
407}
Defines detector header information.

References detector_header_.

Referenced by readGlobalAuxInfo().

◆ createMagneticField()

void simcore::geo::AuxInfoReader::createMagneticField ( const G4String & name,
const G4GDMLAuxListType * auxInfoList )
private

Create a magnetic field from GDML data.

Parameters
nameThe name of the magnetic field.
auxInfoListThe aux info defining the magnetic field.

Definition at line 134 of file AuxInfoReader.cxx.

135 {
136 // Find type of the mag field.
137 G4String mag_field_type("");
138 for (const auto& aux_info : *auxInfoList) {
139 G4String aux_type = aux_info.type;
140 G4String aux_val = aux_info.value;
141
142 if (aux_type == "MagneticFieldType") {
143 mag_field_type = aux_val;
144 break;
145 }
146 }
147
148 if (mag_field_type == "") {
149 EXCEPTION_RAISE("MissingInfo",
150 "Missing MagFieldType for magnetic field definition.");
151 }
152
153 G4MagneticField* mag_field = nullptr;
154
155 // Create a uniform mag field using the built-in Geant4 type.
156 if (mag_field_type == "G4UniformMagField") {
157 double bx, by, bz;
158 bx = by = bz = 0.;
159 for (const auto& aux_info : *auxInfoList) {
160 G4String aux_type = aux_info.type;
161 G4String aux_val = aux_info.value;
162 G4String aux_unit = aux_info.unit;
163
164 G4String expr = aux_val + "*" + aux_unit;
165 if (aux_type == "bx") {
166 bx = eval_->Evaluate(expr);
167 } else if (aux_type == "by") {
168 by = eval_->Evaluate(expr);
169 } else if (aux_type == "bz") {
170 bz = eval_->Evaluate(expr);
171 }
172 }
173 G4ThreeVector field_components(bx, by, bz);
174 mag_field = new G4UniformMagField(field_components);
175
176 // G4cout << "Created G4UniformMagField " << magFieldName << " with field
177 // components " << fieldComponents << G4endl << G4endl;
178
179 // Create a global 3D field map by reading from a data file.
180 } else if (mag_field_type == "MagneticFieldMap3D") {
181 string file_name;
182 double offset_x{};
183 double offset_y{};
184 double offset_z{};
185
186 for (const auto& aux_info : *auxInfoList) {
187 G4String aux_type = aux_info.type;
188 G4String aux_val = aux_info.value;
189 G4String aux_unit = aux_info.unit;
190
191 G4String expr = aux_val + "*" + aux_unit;
192
193 if (aux_type == "File") {
194 file_name = aux_val;
195 } else if (aux_type == "OffsetX") {
196 offset_x = eval_->Evaluate(expr);
197 } else if (aux_type == "OffsetY") {
198 offset_y = eval_->Evaluate(expr);
199 } else if (aux_type == "OffsetZ") {
200 offset_z = eval_->Evaluate(expr);
201 }
202 }
203
204 if (file_name.size() == 0) {
205 EXCEPTION_RAISE("MissingInfo",
206 "File info with field data was not provided.");
207 }
208
209 // Create new 3D field map.
210 mag_field =
211 new MagneticFieldMap3D(file_name.c_str(), offset_x, offset_y, offset_z);
212
213 // Assign field map as global field.
214 G4FieldManager* field_mgr =
215 G4TransportationManager::GetTransportationManager()->GetFieldManager();
216 if (field_mgr->GetDetectorField() != nullptr) {
217 EXCEPTION_RAISE("MisAssign", "Global mag field was already assigned.");
218 }
219 field_mgr->SetDetectorField(mag_field);
220 field_mgr->CreateChordFinder(mag_field);
221
222 } else {
223 EXCEPTION_RAISE("UnknownType", "Unknown MagFieldType '" +
224 std::string(mag_field_type.data()) +
225 "' in auxiliary info.");
226 }
227
228 MagneticFieldStore::getInstance()->addMagneticField(magFieldName, mag_field);
229}
void addMagneticField(const std::string &name, G4MagneticField *magField)
Add a magnetic field by name.

References simcore::MagneticFieldStore::addMagneticField(), eval_, and simcore::MagneticFieldStore::getInstance().

Referenced by readGlobalAuxInfo().

◆ createRegion()

void simcore::geo::AuxInfoReader::createRegion ( const G4String & name,
const G4GDMLAuxListType * auxInfoList )
private

Create a detector region from GDML data.

Parameters
nameThe name of the detector region.
auxInfoListThe aux info defining the detector region.

Definition at line 231 of file AuxInfoReader.cxx.

232 {
233 bool store_trajectories = true;
234 for (const auto& aux_info : *auxInfoList) {
235 G4String aux_type = aux_info.type;
236 G4String aux_val = aux_info.value;
237
238 if (aux_type == "StoreTrajectories") {
239 if (aux_val == "false") {
240 store_trajectories = false;
241 } else if (aux_val == "true") {
242 store_trajectories = true;
243 }
244 }
245 }
246 G4VUserRegionInformation* region_info =
247 new UserRegionInformation(store_trajectories);
248 // This looks like a memory leak, but isn't. I (Einar) have checked. Geant4
249 // registers the region in the constructor and deletes it at the end.
250 //
251 // Some static analysis tools may struggle with identifying that this one
252 // happens to be fine. The NOLINT comment tells clang-tidy to not bother
253 // within the region
254 //
255 // NOLINTBEGIN
256 auto region = new G4Region(name);
257 region->SetUserInformation(region_info);
258 // To get rid of those pesky G4 warnings
259 region->SetProductionCuts(G4ProductionCutsTable::GetProductionCutsTable()
260 ->GetDefaultProductionCuts());
261}

Referenced by readGlobalAuxInfo().

◆ createVisAttributes()

void simcore::geo::AuxInfoReader::createVisAttributes ( const G4String & name,
const G4GDMLAuxListType * auxInfoList )
private

Create visualization attributes from GDML data.

Parameters
nameThe name of the visualization attributes.
auxInfoListThe aux info defining the visualization attributes.

Definition at line 291 of file AuxInfoReader.cxx.

292 {
293 std::array<G4double, 4> rgba = {1., 1., 1., 1.};
294 G4bool visible = true;
295 G4bool dau_invisible = false;
296 G4bool force_wireframe = false;
297 G4bool force_solid = false;
298 G4double line_width = 1.0;
299 G4VisAttributes::LineStyle line_style = G4VisAttributes::unbroken;
300
301 // There are some visattributes which should be accepted regardless of mode
302 universal_visattributes_ = {
303 "InvisibleNoDau", "InvisibleShowDau", "NoDau", "GrayWireFrame",
304 "BlueWireFrame", "BlueSolid", "Invisible", "SpVis"};
305 auto match = std::find(universal_visattributes_.begin(),
306 universal_visattributes_.end(), name);
307
308 // If a visattribute is not universal, a color mode is set, and the
309 // visattribute doesn't match the current mode, don't register it
310 if (match == universal_visattributes_.end() && color_mode_ != "" &&
311 name.find(color_mode_) == std::string::npos) {
312 ldmx_log(debug) << "VisAttribute " << name
313 << " doesn't match current mode. Skipping...";
314 return;
315 // Note that if color mode is not set, the last visattributes
316 // defined for each volume will be the active ones
317 }
318
319 for (const auto& aux_info : *auxInfoList) {
320 G4String aux_type = aux_info.type;
321 G4String aux_val = aux_info.value;
322
323 if (aux_type == "R") {
324 rgba[0] = atof(aux_val.c_str());
325 } else if (aux_type == "G") {
326 rgba[1] = atof(aux_val.c_str());
327 } else if (aux_type == "B") {
328 rgba[2] = atof(aux_val.c_str());
329 } else if (aux_type == "A") {
330 rgba[3] = atof(aux_val.c_str());
331 } else if (aux_type == "Style") {
332 if (aux_val == "wireframe") {
333 force_wireframe = true;
334 } else if (aux_val == "solid") {
335 force_solid = true;
336 }
337 } else if (aux_type == "DaughtersInvisible") {
338 if (aux_val == "true") {
339 dau_invisible = true;
340 } else if (aux_val == "false") {
341 dau_invisible = false;
342 }
343 } else if (aux_type == "Visible") {
344 if (aux_val == "true") {
345 visible = true;
346 } else if (aux_val == "false") {
347 visible = false;
348 }
349 } else if (aux_type == "LineStyle") {
350 if (aux_val == "unbroken") {
351 line_style = G4VisAttributes::unbroken;
352 } else if (aux_val == "dashed") {
353 line_style = G4VisAttributes::dashed;
354 } else if (aux_val == "dotted") {
355 line_style = G4VisAttributes::dotted;
356 }
357 } else if (aux_type == "LineWidth") {
358 line_width = atof(aux_val.c_str());
359 }
360 }
361
362 auto vis_attributes = new G4VisAttributes();
363 vis_attributes->SetColor(rgba[0], rgba[1], rgba[2], rgba[3]);
364 vis_attributes->SetVisibility(visible);
365 vis_attributes->SetDaughtersInvisible(dau_invisible);
366 vis_attributes->SetForceWireframe(force_wireframe);
367 vis_attributes->SetForceSolid(force_solid);
368 vis_attributes->SetLineWidth(line_width);
369 vis_attributes->SetLineStyle(line_style);
370 VisAttributesStore::getInstance()->addVisAttributes(name, vis_attributes);
371
372 // G4cout << "Created VisAttributes " << name << G4endl << (*visAttributes) <<
373 // G4endl << G4endl;
374}
void addVisAttributes(const std::string &name, G4VisAttributes *visAttributes)
Register a vis attributes by name.

References simcore::VisAttributesStore::addVisAttributes(), color_mode_, and simcore::VisAttributesStore::getInstance().

Referenced by readGlobalAuxInfo().

◆ getDetectorHeader()

ldmx::DetectorHeader * simcore::geo::AuxInfoReader::getDetectorHeader ( )
inline

Get the detector header that was created from the userinfo block.

Returns
The detector header.

Definition at line 56 of file AuxInfoReader.h.

56{ return detector_header_; }

References detector_header_.

◆ readGlobalAuxInfo()

void simcore::geo::AuxInfoReader::readGlobalAuxInfo ( )

Read the global auxiliary information from the auxinfo block.

Definition at line 41 of file AuxInfoReader.cxx.

41 {
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 == "ColorMode") {
57 selectColorMode(aux_val);
58 } else if (aux_type == "VisAttributes") {
59 createVisAttributes(aux_val, aux_info.auxList);
60 } else if (aux_type == "DetectorVersion") {
61 createDetectorHeader(aux_val, aux_info.auxList);
62 }
63 }
64 return;
65}
void createDetectorHeader(const G4String &detectorVersion, const G4GDMLAuxListType *auxInfoList)
Create the detector header from the global auxinfo.
void createVisAttributes(const G4String &name, const G4GDMLAuxListType *auxInfoList)
Create visualization attributes from GDML data.
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.
void selectColorMode(const G4String &mode)
Select the 'mode' for coloring in the visualization.

References createDetectorHeader(), createMagneticField(), createRegion(), createVisAttributes(), parser_, and selectColorMode().

◆ selectColorMode()

void simcore::geo::AuxInfoReader::selectColorMode ( const G4String & mode)
private

Select the 'mode' for coloring in the visualization.

Parameters
nameThe selected mode

Definition at line 264 of file AuxInfoReader.cxx.

264 {
265 // Chooses which coloring scheme to use for the visattributes
266 // Currently (March 2026) there are two modes implemented:
267 // Region: Only visattributes with "Region" in the name will be applied
268 // Material: Only visattributes with "Material" in the name will be applied
269 // The Region mode colors all volumes in the same subdetector the same color
270 // For example, all volumes in the HCal will be colored orange
271 // The Material mode colors each volume based on which material it's made from
272 //'Unimportant' materials (like glue) are left uncolored or invisible
273 // To add more modes follow these steps:
274 // 1) Make more visattributes in 'visattributes.gdml'
275 // Your new attribute names must share a common string, like "Region"
276 // 2) Add the shared string as a valid option in this function
277
278 std::vector<std::string> valid_modes = {"Region", "Material"};
279
280 auto match = std::find(valid_modes.begin(), valid_modes.end(), mode);
281
282 if (match == valid_modes.end()) {
283 EXCEPTION_RAISE("InvalidMode", "Color mode setting " + mode +
284 " doesn't match any available modes!");
285 }
286
287 // If the input matches a valid mode (doesn't matter which one), proceed
288 color_mode_ = mode;
289}

References color_mode_.

Referenced by readGlobalAuxInfo().

Member Data Documentation

◆ color_mode_

std::string simcore::geo::AuxInfoReader::color_mode_
private

Color mode for visattributes.

Definition at line 115 of file AuxInfoReader.h.

Referenced by assignAuxInfoToVolumes(), createVisAttributes(), and selectColorMode().

◆ detector_header_

ldmx::DetectorHeader* simcore::geo::AuxInfoReader::detector_header_ {nullptr}
private

Detector header with name and version.

Definition at line 110 of file AuxInfoReader.h.

110{nullptr};

Referenced by createDetectorHeader(), getDetectorHeader(), and ~AuxInfoReader().

◆ eval_

G4GDMLEvaluator* simcore::geo::AuxInfoReader::eval_
private

The GDML expression evaluator.

Definition at line 105 of file AuxInfoReader.h.

Referenced by createMagneticField(), and ~AuxInfoReader().

◆ parser_

G4GDMLParser* simcore::geo::AuxInfoReader::parser_
private

The GDML parser.

Definition at line 100 of file AuxInfoReader.h.

Referenced by assignAuxInfoToVolumes(), and readGlobalAuxInfo().

◆ universal_visattributes_

std::vector<std::string> simcore::geo::AuxInfoReader::universal_visattributes_
private

Definition at line 116 of file AuxInfoReader.h.


The documentation for this class was generated from the following files: