Skip to main content

Running a Simulation

This guide walks through running your first simulation using the SIR model with US population data.

1. Check available populations​

curl https://epyscenario-api.isi.it/api/v1/populations

Pick a population name from the list. We'll use United_States. See Population Presets for the full set of options (contact sources, layers, age-group remapping) and Custom Populations for inline age groups and contact matrices.

2. Check available presets​

curl https://epyscenario-api.isi.it/api/v1/models/presets

We'll use the SIR preset. See Model Presets for the SIR / SEIR / SIS / V-SEIR / V-SEIHR compartments and default parameters, or Custom Models to define your own compartments and transitions.

3. Send a simulation request​

curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "SIR",
"parameters": {
"R0": 2.5,
"recovery_rate": 0.1
}
},
"population": {
"name": "United_States"
},
"simulation": {
"start_date": "2024-01-01",
"end_date": "2024-06-01",
"Nsim": 10
},
"initial_conditions": {
"method": "percentage",
"initial_percentages": {"Infected": 0.1}
}
}'

The initial_conditions block seeds the compartments at the start of the simulation. Here, 0.1% of the population is placed in Infected and the rest in Susceptible. Omit the block entirely and ~0.05% of each age group is seeded as Infected by default; switch method to "absolute" to set exact per-age counts. See Initial Conditions for the full reference.

4. Read the response​

The response contains metadata, results, warnings, and a status field. By default the API returns everything: all compartments and transitions, all age groups (plus total), all seven standard quantiles, and a summary with peaks and cumulative totals per age group. You can narrow any of these via output (see Customizing output).

{
"simulation_id": "sim_c9617343b215",
"status": "completed",
"metadata": {
"model": {
"preset": "SIR",
"compartments": ["Susceptible", "Infected", "Recovered"]
},
"population": {
"name": "United_States",
"contacts_source": "mistry_2021",
"layers": ["home", "work", "school", "community"],
"age_group_mapping": null,
"total": 338120586,
"age_groups": {
"0-4": 18608139,
"5-19": 63540783,
"20-49": 132780169,
"50-64": 63172279,
"65+": 60019216
}
},
"simulation": {
"start_date": "2024-01-01",
"end_date": "2024-06-01",
"Nsim": 10,
"dt": 1.0,
"seed": null,
"resample_frequency": "D"
}
},
"results": {
"compartments": {
"dates": ["2024-01-01", "2024-01-02", "..."],
"data": {
"Susceptible": {
"total": {
"0.5": [337708551.0, 337624028.5, "..."],
"0.025": [337708111.775, 337623521.8, "..."],
"0.975": [337709191.6, 337625019.0, "..."]
}
}
}
},
"transitions": {
"dates": ["2024-01-01", "2024-01-02", "..."],
"data": {
"Susceptible_to_Infected": {
"total": {
"0.5": [73911.0, 84270.0, "..."],
"0.025": [73270.4, 83967.6, "..."],
"0.975": [74350.225, 85011.1, "..."]
}
}
}
},
"summary": {
"peaks": {
"Infected": {
"total": {
"quantiles": {
"0.025": 71966341.525,
"0.5": 71990700.5,
"0.975": 72009849.2
},
"peak_date": "2024-02-21"
},
"0-4": { "quantiles": { "0.5": 3593518.5, "...": 0 }, "peak_date": "2024-02-23" },
"65+": { "quantiles": { "0.5": 8681842.5, "...": 0 }, "peak_date": "2024-02-27" }
}
},
"totals": {
"Susceptible_to_Infected": {
"total": { "quantiles": { "0.025": 281387422.725, "0.5": 281428513.5, "0.975": 281457329.9 } },
"0-4": { "quantiles": { "0.5": 14368532.5, "...": 0 } }
}
}
}
},
"warnings": []
}

Results are organized as quantiles (median, confidence intervals) across simulation runs. Both compartments and transitions follow the same nested structure: name -> age_group -> quantile -> [values]. The total age group is the sum across all age groups.

summary mirrors that shape without the time dimension. peaks is compartment -> age_group -> {quantiles, peak_date} and carries the maximum value reached during the simulation window per quantile. totals is transition -> age_group -> {quantiles} and carries the cumulative number of transition events over the whole window.

warnings is an empty list when there is nothing to report. For example, passing both infectious_period and recovery_rate to a preset uses recovery_rate and returns:

"warnings": [
{
"code": "parameter_overridden",
"parameter": "infectious_period",
"overridden_by": "recovery_rate",
"message": "infectious_period was ignored because recovery_rate was explicitly provided."
}
]

See Warnings for the codes and how to resolve them.

Errors​

A successful run returns HTTP 200 with "status": "completed". If a run cannot complete, the API returns an HTTP error with a detail message instead:

StatusWhen
422The request is invalid. These checks run before the simulation starts. Examples: a date that is not a real YYYY-MM-DD date, an end_date before its start_date, an initial_conditions compartment that is not in the model, an unknown intervention layer, or a transition rate that is negative after evaluation.
504Loading a built-in population timed out. Retry the request.
500An unexpected internal error occurred. The details are logged on the server and not returned.

A simulation needs at least 3 time steps. With the default dt: 1, end_date must be at least 2 days after start_date. The Python export endpoint applies the same input checks.

5. Customizing output​

Everything under output is optional; sensible defaults cover most cases. You can narrow the response with any combination of:

{
"output": {
"quantiles": [0.1, 0.5, 0.9],
"age_groups": ["total"],
"compartments": ["Infected"],
"transitions": ["Susceptible_to_Infected"],
"summary": {
"peak_compartments": ["Infected"],
"total_transitions": []
}
}
}
  • quantiles drives both the trajectory quantiles and the summary quantiles.
  • age_groups filters both the trajectory age groups and the summary age groups. Use ["total"] to skip the per-age breakdown entirely.
  • compartments / transitions filter the trajectory section only.
  • summary.peak_compartments / summary.total_transitions: omit to include every compartment / transition; pass [] to explicitly opt out of that half of the summary. An empty array for both leaves summary: null.

6. Increase Nsim for production use​

Start with Nsim: 10 while testing, then increase to 100 or more for reliable estimates.

7. One-liner example​

For a quick read of one stat from the response, pipe through jq. For example, the median peak of Infected summed across all age groups along with its date:

curl -s -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {"preset": "SIR", "parameters": {"R0": 2.5, "recovery_rate": 0.1}},
"population": {"name": "United_States"},
"simulation": {"start_date": "2024-01-01", "end_date": "2024-06-01", "Nsim": 100}
}' | jq '.results.summary.peaks.Infected.total | {peak_date, median: .quantiles["0.5"]}'
{
"peak_date": "2024-02-26",
"median": 71936946.5
}
tip

Use the API Reference to build and send requests interactively without writing curl commands.

Next​

Try the same request in the Playground to iterate on parameters and see plots without leaving the browser.