Skip to content

engine: unit checker cannot unify 'year' with the implicit 'time' unit of stocks #455

@bpowers

Description

@bpowers

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

  1. 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.
  2. 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.
  3. 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions