Custom Populations
Instead of a preset, you can define a population inline by specifying age groups and contact matrices yourself. This is useful for synthetic populations (homogeneous mixing, toy two-group models) or for plugging in demographics and contact data that aren't available through epydemix.
To opt in, set population.source to "custom" and provide age_groups and contact_matrices.
Structure
A custom population requires two things.
Age groups
A mapping from group name to population count. Insertion order matters: it defines the row and column order used by every contact matrix and by any age-varying parameter.
"age_groups": {
"A": 100000,
"B": 100000
}
Contact matrices
One square matrix per layer, keyed by layer name. Each matrix must be n by n where n = len(age_groups), and rows and columns follow the same order as age_groups. The keys define your layer set: pick names that match anything you'll target with interventions.
"contact_matrices": {
"home": [[0.10, 0.05], [0.05, 0.10]],
"work": [[0.15, 0.20], [0.20, 0.15]]
}
The layer name overall is reserved by epydemix and rejected.
Example: Homogeneous (single group)
The simplest case: one age group and a 1x1 contact matrix. This reproduces the classic homogeneous-mixing compartmental model.
curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "SIR",
"parameters": {"transmission_rate": 0.3, "recovery_rate": 0.1}
},
"population": {
"source": "custom",
"name": "Homogeneous N=100k",
"age_groups": {"A": 100000},
"contact_matrices": {"all": [[1.0]]}
},
"simulation": {
"start_date": "2024-01-01",
"end_date": "2024-06-01",
"Nsim": 50
}
}'
Example: Two age groups
A toy two-group population with a single mixing layer.
curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "SIR",
"parameters": {"transmission_rate": 0.3, "recovery_rate": 0.1}
},
"population": {
"source": "custom",
"name": "Toy two-group",
"age_groups": {"A": 100, "B": 100},
"contact_matrices": {"all": [[0.2, 0.3], [0.3, 0.2]]}
},
"simulation": {
"start_date": "2024-01-01",
"end_date": "2024-01-31",
"Nsim": 5
}
}'
Example: Multiple layers with an intervention
Custom layers can be targeted by interventions just like preset layers. Here a lockdown cuts contacts in the work layer to 50% for ten days.
curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "SIR",
"parameters": {"transmission_rate": 0.3, "recovery_rate": 0.1}
},
"population": {
"source": "custom",
"name": "Two-layer custom",
"age_groups": {"A": 100, "B": 100},
"contact_matrices": {
"home": [[0.10, 0.05], [0.05, 0.10]],
"work": [[0.15, 0.20], [0.20, 0.15]]
}
},
"interventions": [
{
"layer_name": "work",
"start_date": "2024-01-10",
"end_date": "2024-01-20",
"reduction_factor": 0.5,
"name": "lockdown"
}
],
"simulation": {
"start_date": "2024-01-01",
"end_date": "2024-01-31",
"Nsim": 10
}
}'
Validation rules
Requests that violate any of the following return 422:
| Rule | What gets rejected |
|---|---|
age_groups non-empty | {} |
contact_matrices non-empty | {} |
Each matrix is n by n where n = len(age_groups) | row count mismatch, non-square rows |
Layer name is not overall | {"overall": [[...]]} |