Skip to content

Support generic initial_state in simulate config#220

Closed
jc-macdonald wants to merge 2 commits intomainfrom
generic-initial-state
Closed

Support generic initial_state in simulate config#220
jc-macdonald wants to merge 2 commits intomainfrom
generic-initial-state

Conversation

@jc-macdonald
Copy link
Copy Markdown
Contributor

@jc-macdonald jc-macdonald commented Apr 19, 2026

Summary

Generalize the SimulateCommand to support arbitrary-length initial state vectors instead of the hardcoded s0/i0/r0 convention.

Problem

The simulate CLI command hardcodes initial state extraction to exactly three SIR compartments (s0, i0, r0). This makes it impossible to use flepimop2 simulate with models that have more (or fewer) than 3 states — e.g., SIRHD (5 states) or vaccination-structured models (9+ states).

Solution

When a simulate spec includes an initial_state dict, its values are used directly as the state vector and its keys are excluded from the params dict. The legacy s0/i0/r0 fallback is preserved for backward compatibility.

New config usage:

simulate:
  demo:
    times: 0.0:1.0:200.0
    initial_state:
      S: 9990
      I: 10
      H: 0
      R: 0
      D: 0

No schema changes were needed — SimulateSpecificationModel already has ConfigDict(extra="allow"), so the initial_state key is accepted and accessible via getattr.

Note on inference compatibility

The new initial_state path currently takes raw floats, bypassing ParameterABC. This means initial conditions are fixed constants that cannot yet participate in sampling or optimization. However, this does not block future inference support — the dict-of-names structure is well-positioned for it. A future extension just needs to check whether each value is a bare number or a parameter module reference (e.g., {module: distribution, ...}) and route accordingly. The key names are the actual state names, which is a better foundation than the ad-hoc s0/i0/r0 convention.

Changes

  • src/flepimop2/_cli/_simulate_command.py: Generalized initial state extraction (+22/-12 lines)
  • CHANGELOG.md: Added entry under Changed

Testing

  • All 291 existing tests pass (289 unit + 2 integration)
  • ruff and mypy clean

Allow simulate specs to declare an initial_state dict instead of
relying on the hardcoded s0/i0/r0 parameter convention. When
initial_state is present in the simulate block, its values are used
directly as the state vector and its keys are excluded from params.
Falls back to the legacy s0/i0/r0 lookup when initial_state is absent.
Copy link
Copy Markdown
Collaborator

@TimothyWillard TimothyWillard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conceptual question, also this should be a squashed commit if merging

)
target_name = target or next(iter(config_model.simulate))
sim_spec = config_model.simulate[target_name]
raw_initial: dict[str, float] | None = getattr(sim_spec, "initial_state", None)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is moving in a different direction than #211 by putting the initial conditions into the simulate config block rather than the system config block. Is that where we want to have initial conditions be long term? If so #211 probably requires reworking.

@jc-macdonald
Copy link
Copy Markdown
Contributor Author

superseded by #226.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants