gfields
Loading...
Searching...
No Matches
gmagneto.cc
Go to the documentation of this file.
1// gemc
2#include "gfactory.h"
3
4// gfields
5#include "gmagneto.h"
6#include "gfield_options.h"
7
8// guts
9#include <gemc/guts/gutsConventions.h>
10#include <gemc/guts/gutilities.h>
11
12// CLHEP
13#include <CLHEP/Units/SystemOfUnits.h>
14
15// c++
16#include <algorithm>
17#include <cmath>
18#include <exception>
19
20#include "G4TransportationManager.hh"
21#include "G4PropagatorInField.hh"
22
23namespace {
24
25bool is_unset_field_name(const std::string& name) {
26 return name.empty() || name == UNINITIALIZEDSTRINGQUANTITY || name == "not provided";
27}
28
29double configured_max_field_step(const std::shared_ptr<GOptions>& gopts) {
30 if (gopts == nullptr || !gopts->doesOptionExist(MAX_FIELD_STEP_OPTION)) { return 0.0; }
31 return gutilities::getG4Number(gopts->getScalarString(MAX_FIELD_STEP_OPTION));
32}
33
34} // namespace
35
36
37GMagneto::GMagneto(const std::shared_ptr<GOptions>& gopts,
38 const std::set<std::string>& required_fields) : GBase(gopts, GMAGNETO_LOGGER) {
39 // Allocate the registries that will hold field objects and their corresponding managers.
40 fields_map = std::make_shared<gFieldMap>();
41 fields_manager = std::make_shared<gFieldMgrMap>();
42
43 // Factory manager responsible for loading plugins and instantiating objects.
44 GManager gFieldManager(gopts);
45
46 // Translate user configuration (options) into concrete field definitions.
47 // TODO: this should be done in gemc instead and passed to gmagneto? could be kept here
48 std::vector<GFieldDefinition> field_definition_array = gfields::get_GFieldDefinition(gopts);
49
50 for (auto& field_definition : field_definition_array) {
51 std::string name = field_definition.name;
52
53 // When a filter is given, load only the fields that are actually used. Fields no volume
54 // references (e.g. reset via -no_field) have their plugin and map skipped entirely.
55 if (!required_fields.empty() && required_fields.find(name) == required_fields.end()) {
56 log->info(1, "Field <", name, "> is not used by any volume: skipping plugin and map load.");
57 continue;
58 }
59
60 log->info(1, field_definition);
61
62 // Only create each named field once; repeated names are ignored by this map check.
63 if (fields_map->find(name) == fields_map->end()) {
64 // Load the plugin, instantiate the field object, and cache it by name.
65 fields_map->emplace(name, gFieldManager.LoadAndRegisterObjectFromLibrary<GField>(
66 field_definition.gfieldPluginName(), gopts));
67
68 // Pass the configuration down to the concrete implementation so it can parse/cache parameters.
69 fields_map->at(name)->load_field_definitions(field_definition);
70
71 // Create and cache the Geant4 field manager responsible for stepping/chord finding.
72 fields_manager->emplace(name, fields_map->at(name)->create_FieldManager());
73 }
74 }
75
76 const double max_field_step = configured_max_field_step(gopts);
77 if (max_field_step > 0.0) {
78 G4TransportationManager::GetTransportationManager()
79 ->GetPropagatorInField()
80 ->SetLargestAcceptableStep(max_field_step);
81 log->info(1, "Maximum acceptable field step set to ", max_field_step / CLHEP::mm, " mm.");
82 }
83}
84
86 const std::shared_ptr<GOptions>& gopts, double& field_polarity,
87 std::shared_ptr<GLogger> caller_log) {
88 if (gopts == nullptr) { return nullptr; }
89
90 if (gopts->doesOptionExist(NO_FIELD_OPTION)) {
91 const std::string no_field_value = gopts->getScalarString(NO_FIELD_OPTION);
92 if (no_field_value == NO_FIELD_ALL) {
93 if (caller_log != nullptr) {
94 caller_log->info(1, "Global field reset by -", NO_FIELD_OPTION, "=", NO_FIELD_ALL,
95 ": direct field probes disabled.");
96 }
97 return nullptr;
98 }
99 }
100
101 if (!gopts->doesOptionExist(GLOBAL_FIELD_OPTION)) { return nullptr; }
102
103 const std::string field_name = gopts->getScalarString(GLOBAL_FIELD_OPTION);
104 if (is_unset_field_name(field_name)) { return nullptr; }
105
106 for (const auto& field_definition : gfields::get_GFieldDefinition(gopts)) {
107 if (field_definition.name != field_name) { continue; }
108
109 const auto torus_scale_it = field_definition.field_parameters.find("torus_scale");
110 if (torus_scale_it != field_definition.field_parameters.end()) {
111 try {
112 field_polarity = std::stod(torus_scale_it->second) < 0.0 ? -1.0 : 1.0;
113 } catch (const std::exception&) {
114 if (caller_log != nullptr) {
115 caller_log->warning("Could not parse torus_scale <", torus_scale_it->second,
116 "> for field polarity; using +1.");
117 }
118 field_polarity = 1.0;
119 }
120 }
121 break;
122 }
123
124 auto magneto = std::make_unique<GMagneto>(gopts, std::set<std::string>{field_name});
125 if (magneto->isField(field_name)) {
126 if (caller_log != nullptr) {
127 caller_log->info(1, "Using magnetic field <", field_name,
128 "> for direct probes with torus polarity ", field_polarity);
129 }
130 return magneto->getField(field_name);
131 }
132
133 if (caller_log != nullptr) {
134 caller_log->warning("Global field <", field_name,
135 "> is configured but was not available for direct probes.");
136 }
137 return nullptr;
138}
139
141 const std::shared_ptr<GField>& magnetic_field, const G4ThreeVector& position) {
142 using namespace CLHEP;
143
144 if (magnetic_field == nullptr) { return 0.0; }
145
146 const double point[3] = {position.x(), position.y(), position.z()};
147 double bfield[3] = {0.0, 0.0, 0.0};
148 magnetic_field->GetFieldValue(point, bfield);
149
150 return std::sqrt(bfield[0] * bfield[0] + bfield[1] * bfield[1] + bfield[2] * bfield[2]) / tesla;
151}
152
153std::vector<std::string> GMagneto::getFieldNames() const {
154 std::vector<std::string> names;
155 names.reserve(fields_map->size());
156 for (const auto& [name, field] : *fields_map) { names.push_back(name); }
157 std::sort(names.begin(), names.end());
158 return names;
159}
std::shared_ptr< GLogger > log
Abstract base class representing a magnetic field.
Definition gfield.h:105
void info(int level, Args &&... args) const
GMagneto(const std::shared_ptr< GOptions > &gopts, const std::set< std::string > &required_fields={})
Construct and initialize the magnetic field registry.
Definition gmagneto.cc:37
static double magnetic_field_magnitude_tesla(const std::shared_ptr< GField > &magnetic_field, const G4ThreeVector &position)
Return the magnetic-field magnitude at a position in Tesla.
Definition gmagneto.cc:140
std::vector< std::string > getFieldNames() const
Return the configured field names.
Definition gmagneto.cc:153
static std::shared_ptr< GField > initialize_magnetic_field(const std::shared_ptr< GOptions > &gopts, double &field_polarity, std::shared_ptr< GLogger > caller_log=nullptr)
Load the configured global magnetic field for code that needs direct field probes.
Definition gmagneto.cc:85
std::shared_ptr< T > LoadAndRegisterObjectFromLibrary(std::string_view name, const std::shared_ptr< GOptions > &gopts)
constexpr const char * GMAGNETO_LOGGER
Definition gfield.h:14
double position[3]
#define NO_FIELD_ALL
Special NO_FIELD_OPTION value that resets all fields, including GLOBAL_FIELD_OPTION.
#define NO_FIELD_OPTION
Command-line option name used to reset (remove) field associations.
#define GLOBAL_FIELD_OPTION
Command-line option name used to associate a field with the ROOT world volume.
#define MAX_FIELD_STEP_OPTION
Command-line option name used to set the global maximum acceptable field step.
#define UNINITIALIZEDSTRINGQUANTITY
std::vector< GFieldDefinition > get_GFieldDefinition(const std::shared_ptr< GOptions > &gopts)
Build the list of field definitions from the provided options.
double getG4Number(const string &v, bool warnIfNotUnit=false)