Description
Stocks inherit an implicit time unit in their stored-value / attached-flow relationship, but models routinely annotate their flows with the model's declared time unit (e.g. year). The unit checker treats time and year as distinct unit names and cannot unify them, producing a large class of spurious errors.
Representative CLI output (./target/release/simlin simulate --no-output test/metasd/WRLD3-03/wrld3-03.mdl):
units error in model 'main' variable 'resource_usage_rate': unit_mismatch -- expected units 'resource_units/year' to match the units expected by the attached stock nonrenewable_resources (resource_units/time)
units error in model 'main' variable 'land_life_multiplier_from_land_yield': unit_mismatch -- expected left and right argument units to match, but 'time' and 'year' don't
units error in model 'main' variable 'service_capital_investment': unit_mismatch -- expected units '$/year' to match the units expected by the attached stock service_capital ($/time)
World3 emits 20+ variants of this message across its flow-into-stock relationships. The same failure mode will appear on any model whose time_units is a concrete physical time unit (year, month, day, s, ...) rather than the literal string time.
Why it matters
- Every multi-stock model with annotated units trips this when
time_units is anything other than time. The resulting wall of noise hides genuine errors.
- Stock/flow unit compatibility is the single most useful unit check in SD modeling -- the one that catches flow-direction mistakes and missing
/time denominators. Getting it wrong breaks the tool's core value for unit checking.
Components affected
src/simlin-engine/src/units_check.rs -- stock/flow pairwise compatibility check
src/simlin-engine/src/units_infer.rs -- likely introduces the time literal as the stock's time dimension during inference
Possible approaches
- Canonicalize the stock's time dimension to the project's declared
time_units at unit-map construction time. time becomes year (or whatever the model declared) and unification succeeds by plain equality.
- Teach the unifier that
time is a placeholder that matches any unit declared as the project's time dimension -- analogous to how 1 (dimensionless) is handled.
- Expose
time_units in the unit inference context and perform the substitution eagerly.
Option 1 is simplest and avoids special cases in the unifier. It does mean the stock's time dimension identifier changes per project, which must be plumbed through inference.
Context
Discovered while fixing the delay3 conflation bug in commit 6d48816. The previous bug masked this one: once the spurious input-vs-delay_time conflicts were gone, the flow-vs-stock time-unit conflicts dominated the output.
Related: #35 (general unit checking tracker).
Description
Stocks inherit an implicit
timeunit in their stored-value / attached-flow relationship, but models routinely annotate their flows with the model's declared time unit (e.g.year). The unit checker treatstimeandyearas distinct unit names and cannot unify them, producing a large class of spurious errors.Representative CLI output (
./target/release/simlin simulate --no-output test/metasd/WRLD3-03/wrld3-03.mdl):World3 emits 20+ variants of this message across its flow-into-stock relationships. The same failure mode will appear on any model whose
time_unitsis a concrete physical time unit (year, month, day, s, ...) rather than the literal stringtime.Why it matters
time_unitsis anything other thantime. The resulting wall of noise hides genuine errors./timedenominators. Getting it wrong breaks the tool's core value for unit checking.Components affected
src/simlin-engine/src/units_check.rs-- stock/flow pairwise compatibility checksrc/simlin-engine/src/units_infer.rs-- likely introduces thetimeliteral as the stock's time dimension during inferencePossible approaches
time_unitsat unit-map construction time.timebecomesyear(or whatever the model declared) and unification succeeds by plain equality.timeis a placeholder that matches any unit declared as the project's time dimension -- analogous to how1(dimensionless) is handled.time_unitsin the unit inference context and perform the substitution eagerly.Option 1 is simplest and avoids special cases in the unifier. It does mean the stock's time dimension identifier changes per project, which must be plumbed through inference.
Context
Discovered while fixing the delay3 conflation bug in commit 6d48816. The previous bug masked this one: once the spurious input-vs-delay_time conflicts were gone, the flow-vs-stock time-unit conflicts dominated the output.
Related: #35 (general unit checking tracker).