DESModel
models.DESModel(
process,
population=None,
interventions,
resources=None,
horizon,
discount_rate=0.03,
n_individuals=1000,
effect='qaly',
independent_streams=False,
)Discrete-event simulation engine wrapping SimPy.
Each process is the user’s own SimPy code with signature process(env, entity, params, intervention, toolkit). entity is that individual’s attribute row, params the iteration’s draw merged with the intervention decision levers, intervention the intervention name, and toolkit the _DESToolkit that accrues cost and effect and logs the trajectory. Per iteration and intervention the engine builds the environment, samples entities, creates the shared resources, runs every process to horizon, collects the per-entity discounted accruals, averages them, and writes one Outcomes row.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| process | ProcessFn |
The SimPy process factory, fn(env, entity, params, intervention, toolkit) returning a generator. |
required |
| population | PopulationSpec |
Attribute sampler fn(rng, n) -> DataFrame, an int count for a featureless population, or None to use n_individuals with no attributes. |
None |
| interventions | InterventionSpec |
A sequence of intervention names or heormodel.models.Intervention objects; an Intervention may carry parameter decision levers merged into params for that intervention. Order is preserved in Outcomes. |
required |
| resources | ResourceFn | None |
fn(env, params, intervention) -> dict[str, simpy.Resource], built fresh for each run and shared by every entity in it. None for a model with no constrained resources. |
None |
| horizon | float |
Time horizon in the environment’s unit; the run stops here. Each process reads it back as toolkit.horizon. |
required |
| discount_rate | float |
Annual (per-unit-time) discount rate for costs and effects (0.03 by default). Discounting is continuous (exp(-rate * t)). |
0.03 |
| n_individuals | int |
Population size when population is a sampler or None. |
1000 |
| effect | str |
Name of the effect column (QALYs by default). | 'qaly' |
| independent_streams | bool |
Give each intervention its own population and streams instead of common random numbers. | False |
Randomness is supplied by heormodel.run.run_psa at run time, not at construction; the engine holds no seed of its own.
Example
import numpy as np, pandas as pd from heormodel.models import DESModel def process(env, entity, params, intervention, toolkit): … wait = toolkit.rng.exponential(params[“los”]) … toolkit.accrue_rate(params[“day_cost”], 1.0, wait) … yield env.timeout(wait) engine = DESModel( … process=process, population=200, interventions=[“ward”], … horizon=30.0) draws = pd.DataFrame({“los”: [3.0], “day_cost”: [500.0]}, … index=pd.RangeIndex(1, name=“iteration”)) engine.evaluate(draws).interventions [‘ward’]
Methods
| Name | Description |
|---|---|
| evaluate | Simulate every draw and intervention, averaging entities to Outcomes. |
| evaluate_streamed | Simulate every draw under streams, collecting the collect log. |
evaluate
models.DESModel.evaluate(draws)Simulate every draw and intervention, averaging entities to Outcomes.
This is the narrow heormodel.models.ModelEngine entry point: it seeds each iteration from a fixed default stream, so a direct call is reproducible. Run through heormodel.run.run_psa to choose the seed, to run in parallel, and to collect the event or individual logs.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| draws | pd.DataFrame | Parameter draw matrix (rows = iterations). Its index becomes the outcome iteration index. | required |
Returns
| Name | Type | Description |
|---|---|---|
| Outcomes | Outcomes indexed by (intervention, draws.index). |
Example
import pandas as pd from heormodel.models import DESModel def process(env, entity, params, intervention, toolkit): … toolkit.accrue_cost(params[“visit”]) … yield env.timeout(1.0) engine = DESModel( … process=process, population=50, interventions=[“clinic”], … horizon=5.0) draws = pd.DataFrame({“visit”: [200.0, 210.0]}, … index=pd.RangeIndex(2, name=“iteration”)) engine.evaluate(draws).n_iterations 2
evaluate_streamed
models.DESModel.evaluate_streamed(draws, *, streams, collect=None)Simulate every draw under streams, collecting the collect log.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| draws | pd.DataFrame | Parameter draw matrix (rows = iterations). | required |
| streams | SeedManager | Root of the per-iteration streams; each iteration draws a stream keyed by its index, so results do not depend on how the run is chunked across workers. | required |
| collect | str | None |
None for outcomes only, "events" for the per-entity event log (columns intervention, iteration, entity, t, event, state, resource), or "individuals" for per-entity cost and effect. |
None |
Returns
| Name | Type | Description |
|---|---|---|
EngineResult |
An EngineResult whose outcomes is always set and whose |
|
EngineResult |
events or individuals is set to match collect. |