|
FhSim
3.1.0
Marine systems simulation
|
| ID | 0019 |
| Class | KNOWN-LIMITATION |
| Severity | 2 |
| Status | blocked |
| Models | Environment |
| Found | 2026-09-22 while adding ScalarField.<Name>.Model = "Parametric" |
| Decision needed | Wait for fhsim issue core,0004 (recommended fix there: an additive GetRawStringParam), or drop the inline Config parameters here in favour of ConfigFile only? |
| Upstream | fhsim issue core,0004 — same defect, filed at its root |
The FhSim XML parameter reader does not hand a string parameter back verbatim. It splits the attribute value on commas, reformats every token that parses as a number, and rejoins with a comma. A numeric literal immediately followed by ] is consumed whole by the numeric conversion, so the bracket is lost.
Root cause, traced into the fhsim package and filed there as issue core,0004. It is not in GetStringParam, which is a plain map lookup (fhsim/src/simobject/SimObjectOrganizer.cpp:248-259) and by then already has the rewritten text. The rewrite happens at fhsim/src/engine/core/Parse.cpp:422, which calls ExpressionEvaluator::EvaluateExpressions(sValue) unconditionally on every attribute of every SimObject element before storing it. EvaluateExpressions (fhsim/src/simobject/utilities/ExpressionEvaluator.cpp:33) splits on commas and hands any token containing no ASCII letter to a shunting-yard arithmetic evaluator that is not bracket aware. That is exactly why the damage is selective: "depth": [0.0 contains letters and is skipped, while 60] does not and is mangled. So the limitation is ecosystem-wide, not a property of this library or of string parameters specifically.
There is an undocumented escape hatch. EvaluateExpressions returns immediately if the value contains a ; (ExpressionEvaluator.cpp:47, intended to protect Windows paths and unit strings). A semicolon anywhere in the attribute therefore disables evaluation for the whole value, and a JSON document can legitimately carry one inside any string member. This has not been adopted here because it relies on an accident of the number-list heuristic rather than a designed opt-out, and a future tightening of that heuristic would silently break every input file that depended on it. It is recorded because it is the only known way to pass inline structured text today, and because whoever fixes core,0004 needs to know it exists.
Reproduced by instrumenting the catch block at src/environment/util/parameters.cpp:511, which was made to report the document it received, and running tests/in/ParametricFields/ParametricFields_in.xml with this attribute:
What ISimObjectCreator::GetStringParam returned:
Three separate changes are visible: 3.0 became 3, 5.0e-5 became 5e-05, and both ] characters that directly followed a number are gone. A bracket that follows a space and a brace, as in 7.0e-3 } ], survives, because that token does not parse as a number.
nlohmann::json then fails with
The same reader serves Bathymetry.Config (src/environment/util/parameters.cpp:215-224), so environmentmodels::ParametricBathymetry has the identical limitation for its center, end_slopes and points arrays. The existing inline example at tests/in/ParametricSeafloor/ParametricSeafloor_in.xml:14 happens to use only arrays of objects, so the defect has never been hit there.
Any inline Config JSON containing an array of numbers fails to parse. For a scalar field that means a depth profile background, a blob centre, a blob sigma and a domain box - that is, everything except a constant background with depth_band features.
The failure is at least loud: the parse error is reported through ReportParameterError and stops the run. It is, however, baffling, because the text in the input file is valid JSON and the reported column does not correspond to anything the author wrote.
The practical consequence today is that ScalarField.<Name>.ConfigFile is the only usable route for a realistic field, and Config is a trap for anyone who starts from examples/input/auv_ocean_fields.json and pastes an entry into an attribute.
Environment Doxygen and in the JSON schema that an inline Config must not contain an array of numbers, and point at ConfigFile. Done for ScalarField.* as part of the change that found this; Bathymetry.Config still needs the same note. Cheapest, and correct if no verbatim accessor exists.ISimObjectCreator gains a GetRawStringParam, both Config parameters become usable and the note goes away. That is a change in the fhsim package, not here, and it is the only fix that makes the documented parameter work as documented.] from a lost } - and a heuristic that silently reinterprets a user's configuration is exactly the failure mode this field type was written to avoid.Option 1 is what has been done. Option 2 is the real fix, and needing someone outside this package is why the status is blocked rather than ready.
Restore a numeric array in the inline attribute of tests/in/ParametricFields/ParametricFields_in.xml, for example
SimObject.ParametricFields in tests/ParametricScalarField_Test.cpp then fails with the parse_error.101 shown above. Putting the identical document in a file referenced by ScalarField.Cod.ConfigFile makes it pass, which isolates the parameter reader rather than the JSON parser.
Option 1 is documentation only.
Option 2 touches a shared FhSim accessor used by every SimObject in every package. Any change to how attribute values are tokenised could alter how an existing comma-separated vector parameter is read, so it needs a regression pass across the fhsim_* tree, not just this one.