11#include " gfield_options.h"
22#include " gfieldConventions.h"
3+ #include " gmagneto.h"
4+
5+ // geant4
6+ #include " G4UnitsTable.hh"
37
48// gemc
59#include " gutilities.h"
610#include " gfactory_options.h"
11+ #include " goptionsConventions.h"
12+
13+ // c++
14+ #include < cmath>
15+ #include < cstdlib>
16+ #include < fstream>
17+ #include < iostream>
18+ #include < sstream>
719
8- // namespace to define options
920namespace gfields {
1021
11- // Build field definitions by reading the option tree and translating each entry into a GFieldDefinition (non-Doxygen summary).
22+ namespace {
23+
24+ struct FieldQueryPoint {
25+ double position[3 ] = {0.0 , 0.0 , 0.0 };
26+ std::string source;
27+ int line = 0 ;
28+ };
29+
30+ bool is_query_set (const std::string& value) {
31+ return !value.empty () && value != UNINITIALIZEDSTRINGQUANTITY && value != " not provided" ;
32+ }
33+
34+ FieldQueryPoint parse_field_query_point (const std::string& expression, const std::string& source, int line) {
35+ std::string cleaned = expression;
36+ if (const auto comment = cleaned.find (' #' ); comment != std::string::npos) {
37+ cleaned = cleaned.substr (0 , comment);
38+ }
39+ for (auto & c : cleaned) {
40+ if (c == ' ,' ) { c = ' ' ; }
41+ }
42+ cleaned = gutilities::removeLeadingAndTrailingSpacesFromString (cleaned);
43+
44+ FieldQueryPoint point;
45+ point.source = source;
46+ point.line = line;
47+
48+ if (cleaned.empty ()) { return point; }
49+
50+ std::istringstream tokens (cleaned);
51+ std::string x;
52+ std::string y;
53+ std::string z;
54+ std::string extra;
55+ tokens >> x >> y >> z >> extra;
56+ if (x.empty () || y.empty () || z.empty () || !extra.empty ()) {
57+ std::cerr << FATALERRORL << " field query point must contain exactly three coordinates with units" ;
58+ if (line > 0 ) { std::cerr << " at " << source << " :" << line; }
59+ else { std::cerr << " in " << source; }
60+ std::cerr << " . Got <" << expression << " >." << std::endl;
61+ std::exit (EC__G4NUMBERERROR );
62+ }
63+
64+ point.position [0 ] = gutilities::getG4Number (x, true );
65+ point.position [1 ] = gutilities::getG4Number (y, true );
66+ point.position [2 ] = gutilities::getG4Number (z, true );
67+ return point;
68+ }
69+
70+ bool is_blank_or_comment_line (const std::string& line) {
71+ const auto trimmed = gutilities::removeLeadingAndTrailingSpacesFromString (line);
72+ return trimmed.empty () || trimmed[0 ] == ' #' ;
73+ }
74+
75+ void append_field_query_file_points (const std::string& filename, std::vector<FieldQueryPoint>& points) {
76+ std::ifstream input (filename);
77+ if (!input) {
78+ std::cerr << FATALERRORL << " can't open field query point file " << filename << " ." << std::endl;
79+ std::exit (EC__FILENOTFOUND );
80+ }
81+
82+ std::string line;
83+ int line_number = 0 ;
84+ while (std::getline (input, line)) {
85+ ++line_number;
86+ if (is_blank_or_comment_line (line)) { continue ; }
87+ points.push_back (parse_field_query_point (line, filename, line_number));
88+ }
89+ }
90+
91+ void print_field_query_result (const std::string& field_name,
92+ const FieldQueryPoint& point,
93+ const double bfield[3 ]) {
94+ const double bmag = std::sqrt (
95+ bfield[0 ] * bfield[0 ] +
96+ bfield[1 ] * bfield[1 ] +
97+ bfield[2 ] * bfield[2 ]);
98+ std::cout << " field=" << field_name
99+ << " source=" << point.source ;
100+ if (point.line > 0 ) { std::cout << " :" << point.line ; }
101+ std::cout << " x=" << G4BestUnit (point.position [0 ], " Length" )
102+ << " y=" << G4BestUnit (point.position [1 ], " Length" )
103+ << " z=" << G4BestUnit (point.position [2 ], " Length" )
104+ << " Bx=" << G4BestUnit (bfield[0 ], " Magnetic flux density" )
105+ << " By=" << G4BestUnit (bfield[1 ], " Magnetic flux density" )
106+ << " Bz=" << G4BestUnit (bfield[2 ], " Magnetic flux density" )
107+ << " |B|=" << G4BestUnit (bmag, " Magnetic flux density" )
108+ << std::endl;
109+ }
110+
111+ } // namespace
112+
113+ // Build field definitions by reading the option tree and translating each entry into a GFieldDefinition.
12114std::vector<GFieldDefinition> get_GFieldDefinition (const std::shared_ptr<GOptions>& gopts) {
13115 std::vector<GFieldDefinition> gfield_defs;
14116
@@ -19,20 +121,31 @@ std::vector<GFieldDefinition> get_GFieldDefinition(const std::shared_ptr<GOption
19121 GFieldDefinition gfield_def = GFieldDefinition ();
20122
21123 // Core identity and integration configuration.
22- gfield_def.name = gopts->get_variable_in_option <std::string>(gmultipoles_item, " name" , goptions::NODFLT );
23- gfield_def.integration_stepper = gopts->get_variable_in_option <std::string>(gmultipoles_item, " integration_stepper" , GFIELD_DEFAULT_INTEGRATION_STEPPER );
24- gfield_def.minimum_step = gutilities::getG4Number (gopts->get_variable_in_option <std::string>(gmultipoles_item, " minimum_step" , GFIELD_DEFAULT_MINIMUM_STEP ));
124+ gfield_def.name = gopts->get_variable_in_option <std::string>(
125+ gmultipoles_item, " name" , goptions::NODFLT );
126+ gfield_def.integration_stepper = gopts->get_variable_in_option <std::string>(
127+ gmultipoles_item, " integration_stepper" , GFIELD_DEFAULT_INTEGRATION_STEPPER );
128+ gfield_def.minimum_step = gutilities::getG4Number (gopts->get_variable_in_option <std::string>(
129+ gmultipoles_item, " minimum_step" , GFIELD_DEFAULT_MINIMUM_STEP ));
25130
26131 // Multipole parameters:
27132 // Values are stored as strings to preserve unit expressions and are parsed later by the concrete field.
28- gfield_def.add_map_parameter (" pole_number" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " pole_number" , goptions::NODFLT ));
29- gfield_def.add_map_parameter (" vx" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " vx" , GFIELD_DEFAULT_VERTEX ));
30- gfield_def.add_map_parameter (" vy" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " vy" , GFIELD_DEFAULT_VERTEX ));
31- gfield_def.add_map_parameter (" vz" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " vz" , GFIELD_DEFAULT_VERTEX ));
32- gfield_def.add_map_parameter (" rotation_angle" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " rotation_angle" , GFIELD_DEFAULT_ROTANGLE ));
33- gfield_def.add_map_parameter (" rotaxis" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " rotaxis" , goptions::NODFLT ));
34- gfield_def.add_map_parameter (" strength" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " strength" , goptions::NODFLT ));
35- gfield_def.add_map_parameter (" longitudinal" , gopts->get_variable_in_option <std::string>(gmultipoles_item, " longitudinal" , " false" ));
133+ gfield_def.add_map_parameter (" pole_number" , gopts->get_variable_in_option <std::string>(
134+ gmultipoles_item, " pole_number" , goptions::NODFLT ));
135+ gfield_def.add_map_parameter (" vx" , gopts->get_variable_in_option <std::string>(
136+ gmultipoles_item, " vx" , GFIELD_DEFAULT_VERTEX ));
137+ gfield_def.add_map_parameter (" vy" , gopts->get_variable_in_option <std::string>(
138+ gmultipoles_item, " vy" , GFIELD_DEFAULT_VERTEX ));
139+ gfield_def.add_map_parameter (" vz" , gopts->get_variable_in_option <std::string>(
140+ gmultipoles_item, " vz" , GFIELD_DEFAULT_VERTEX ));
141+ gfield_def.add_map_parameter (" rotation_angle" , gopts->get_variable_in_option <std::string>(
142+ gmultipoles_item, " rotation_angle" , GFIELD_DEFAULT_ROTANGLE ));
143+ gfield_def.add_map_parameter (" rotaxis" , gopts->get_variable_in_option <std::string>(
144+ gmultipoles_item, " rotaxis" , goptions::NODFLT ));
145+ gfield_def.add_map_parameter (" strength" , gopts->get_variable_in_option <std::string>(
146+ gmultipoles_item, " strength" , goptions::NODFLT ));
147+ gfield_def.add_map_parameter (" longitudinal" , gopts->get_variable_in_option <std::string>(
148+ gmultipoles_item, " longitudinal" , " false" ));
36149
37150 // The type field controls the shared-library plugin name through GFieldDefinition::gfieldPluginName().
38151 gfield_def.type = " multipoles" ;
@@ -71,6 +184,50 @@ GOptions defineOptions() {
71184 };
72185 goptions.defineOption (" gmultipoles" , " define the e.m. gmultipoles" , gmultipoles, help);
73186
187+ goptions.defineOption (
188+ GVariable (" fieldAt" , UNINITIALIZEDSTRINGQUANTITY , " query all configured fields at x y z" ),
189+ " Evaluate all configured electromagnetic fields at one absolute coordinate.\n \n "
190+ " The value must contain three coordinate expressions with units, separated by spaces.\n \n "
191+ " Example: -fieldAt=\" 10*cm 0*mm 2*m\"\n \n " );
192+
193+ goptions.defineOption (
194+ GVariable (" fieldMapPoints" , UNINITIALIZEDSTRINGQUANTITY , " ASCII file of x y z points for field queries" ),
195+ " Evaluate all configured electromagnetic fields at coordinates listed in an ASCII file.\n \n "
196+ " Each non-empty, non-comment line must contain three coordinate expressions with units.\n "
197+ " Coordinates may be separated by spaces or commas. Lines beginning with # are ignored.\n \n "
198+ " Example: -fieldMapPoints=points.txt\n \n " );
199+
74200 return goptions;
75201}
202+
203+ bool runFieldQueries (const std::shared_ptr<GOptions>& gopts) {
204+ const auto field_at = gopts->getScalarString (" fieldAt" );
205+ const auto field_map_points = gopts->getScalarString (" fieldMapPoints" );
206+
207+ if (!is_query_set (field_at) && !is_query_set (field_map_points)) { return false ; }
208+
209+ std::vector<FieldQueryPoint> points;
210+ if (is_query_set (field_at)) { points.push_back (parse_field_query_point (field_at, " fieldAt" , 0 )); }
211+ if (is_query_set (field_map_points)) { append_field_query_file_points (field_map_points, points); }
212+
213+ auto magneto = std::make_shared<GMagneto>(gopts);
214+ auto field_names = magneto->getFieldNames ();
215+ if (field_names.empty ()) {
216+ std::cerr << FATALERRORL << " field query requested, but no electromagnetic fields are configured."
217+ << std::endl;
218+ std::exit (EC__NOOPTIONFOUND );
219+ }
220+
221+ std::cout << " # field query results" << std::endl;
222+ for (const auto & point : points) {
223+ for (const auto & field_name : field_names) {
224+ double bfield[3 ] = {0.0 , 0.0 , 0.0 };
225+ magneto->getField (field_name)->GetFieldValue (point.position , bfield);
226+ print_field_query_result (field_name, point, bfield);
227+ }
228+ }
229+
230+ return true ;
231+ }
232+
76233}
0 commit comments