build_unit_env
Stable function · Units
Tier: stable · Kind: function · Topic: Units
| Julia | TypeScript | Python | Rust | Go |
|---|---|---|---|---|
| not exported | not exported | not exported | build_unit_env | BuildUnitEnv |
Julia
Julia does not export this function.
TypeScript
TypeScript does not export this function.
Python
Python does not export this function.
Rust
pub fn build_unit_env(variables: &IndexMap<String, ModelVariable>) -> (HashMap<String, Unit>, Vec<UnitParseFailure>)
Build a HashMap<String, Unit> environment from model variable metadata,
together with a list of warnings for any variables whose declared unit
string could not be parsed.
A variable is entered into the environment ONLY when its dimension is
actually known. Both an unparseable unit string and a missing one leave
the variable OUT of the map, so propagate_dim yields Dim::Unknown for
it and every expression containing it is skipped for dimensional checking.
Neither case is coerced to dimensionless. Doing so would both HIDE genuine
mismatches (when the variable is used consistently) and MANUFACTURE false
ones (when the real unit was, e.g., m) — and since a provable mismatch is
now a hard validation error, a fabricated dimension would fail the build on
a legitimate file. A model that declares no units at all (a common idiom in
the shared corpus) is therefore simply not dimension-checked, rather than
being treated as an all-dimensionless model in which D(u)/dt = A*sin(w*t)
looks inconsistent.
The two cases are NOT alike, and only one of them is a defect:
- A MISSING
unitsfield is a legitimate choice — the variable is simply not dimension-checked. - An UNPARSEABLE
unitsfield is a HARD ERROR (unit_parse_error, esm-spec §4.8.4). A unit string either resolves against the shared registry or it is a defect in the file: silently treating a typo (1/time,m/s2) as “dimension unknown” disables every dimensional check downstream, which is precisely the class of bug the checker exists to catch. The failures are returned to the caller, which reports each one at the JSON-Pointer of the offending DECLARATION.
Note this is a different case from a genuinely UNDETERMINABLE dimension (a symbolic exponent), which stays a non-blocking warning: there the checker cannot conclude, whereas here the author wrote something that is not a unit.
Example (validate_equation_dimensions)
let doc = load_path(fixture("decay.esm"))?;
let model = &doc.models.as_ref().unwrap()["Decay"];
let (env, failures) = build_unit_env(&model.variables);
assert!(failures.is_empty());
// half_life = log(2) / lambda: seconds on both sides.
validate_equation_dimensions(&model.equations[1], &env)?;
// half_life is in s but lambda is in 1/s.
let wrong = parse_equation("half_life = lambda")?;
let err = validate_equation_dimensions(&wrong, &env).unwrap_err();
println!("{err}");
assert!(err.to_string().contains("mismatch"));
Go
func BuildUnitEnv(raw map[string]string) (map[string]Unit, map[string]error)
BuildUnitEnv converts a map of name→unit-string into a map of name→Unit. Entries whose unit string fails to parse are omitted from the returned environment and reported in the second return value (a name→parse-error map) so callers can emit warnings. Empty unit strings are skipped without error.