[High] Multipole field parameters bypass unit parsing (stod/stoi ignore unit expressions) · Issue #107 · gemc/src · GitHub
Skip to content

[High] Multipole field parameters bypass unit parsing (stod/stoi ignore unit expressions) #107

Description

@zhaozhiwen

Unit-bearing multipole/dipole field parameters (vx, vy, vz, rotation_angle, strength) are parsed with bare std::stod(), which silently drops any unit expression such as 30*deg, 2*tesla, or 10*cm.

Affected files

  • gemc/gfields/gfield.h:144get_field_parameter_int uses bare stoi
  • gemc/gfields/gfield.h:151get_field_parameter_double uses bare stod
  • gemc/gfields/gfieldFactories/multipoles/gfield_multipoles.cc:160-185 — consumers
  • gemc/gfields/gfield_options.cc:24,28-34 — values stored as unit-bearing strings ("parsed later by the concrete field")

Details

The option layer deliberately keeps multipole parameters as raw strings to preserve unit expressions (gfield_options.cc:27):

// Values are stored as strings to preserve unit expressions and are parsed later by the concrete field.
gfield_def.add_map_parameter("vx", gopts->get_variable_in_option<std::string>(gmultipoles_item, "vx", GFIELD_DEFAULT_VERTEX));
...
gfield_def.add_map_parameter("rotation_angle", ...);
gfield_def.add_map_parameter("strength", ...);

Note that minimum_step in the same file (:24) is correctly run through gutilities::getG4Number(...). But the concrete field reads the others through the bare accessor:

double get_field_parameter_double(const std::string& key) { return stod(gfield_definitions.field_parameters[key]); }

std::stod("30*deg") returns 30.0 and discards *deg — no error, no warning. So rotation_angle, vx/vy/vz, and strength are interpreted in raw internal units (radians, mm, default field unit) regardless of what the user wrote. In load_field_definitions:

origin[0]            = get_field_parameter_double("vx");
origin[1]            = get_field_parameter_double("vy");
origin[2]            = get_field_parameter_double("vz");
rotation_angle       = get_field_parameter_double("rotation_angle");
...
strength             = get_field_parameter_double("strength");

The only integer parameter is pole_number (get_field_parameter_int("pole_number"), :160), a plain count of poles. A pole count must NOT take units, so stoi is correct there and should stay as-is.

Impact

Any multipole/dipole field configured with unit expressions (the documented and natural way to specify 30*deg, 2*tesla, 10*cm) is silently misinterpreted, producing fields with the wrong magnitude, position, and rotation. Failure is silent — the simulation runs and produces physically wrong field maps.

Proposed fix

Route the double accessor through gutilities::getG4Number, which already implements unit-expression parsing. Leave the int accessor on stoi (pole counts are unitless). Add the gutilities.h include since gfield.h does not currently pull it in.

--- a/gemc/gfields/gfield.h
+++ b/gemc/gfields/gfield.h
@@
 #include <gemc/gfactory/gfactory.h>
 #include <gemc/gbase/gbase.h>
+#include <gemc/guts/gutilities.h>
@@
-	int get_field_parameter_int(const std::string& key) { return stoi(gfield_definitions.field_parameters[key]); }
+	int get_field_parameter_int(const std::string& key) { return stoi(gfield_definitions.field_parameters[key]); }
@@
-	double get_field_parameter_double(const std::string& key) { return stod(gfield_definitions.field_parameters[key]); }
+	double get_field_parameter_double(const std::string& key) { return gutilities::getG4Number(gfield_definitions.field_parameters[key]); }

gutilities::getG4Number is declared in gemc/guts/gutilities.h:280:

double getG4Number(const string& v, bool warnIfNotUnit = false);

(Adjust the include path to match how other headers in this module reference gutilities.h; the bracket form above mirrors the existing gfactory.h/gbase.h includes in gfield.h.) No change is needed at the call sites in gfield_multipoles.cc.


Split out from #102 (one issue per bug). Found via an AI-assisted code review with manual verification against commit 5f8ce875.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Live

Relationships

None yet

Development

No branches or pull requests

Issue actions