6. Sobol Sensitivity Analysis
Morris told us which parameters matter and which do not. Sobol goes further by quantifying exactly how much of the output variance each parameter explains — both on its own and through interactions with other parameters. It is the reference method for variance-based global sensitivity analysis.
In particular, this step presents:
- The principle of the Sobol method and its three indices S1 and ST (GAMA doesn't compute S2 in its current state)
- The Saltelli sampling scheme and how to calculate the total number of runs
- How to declare
method soboland configure its facets - How to read and interpret the report file produced by GAMA
The model file for this step can be found in:
msi.gama.models/models/Tutorials/SIR Analysis/models/SIR Model 06.gaml
How Sobol works​
Sobol is a variance-based global sensitivity analysis method. It decomposes the total variance of the output into contributions from each parameter and their interactions:
| Index | Meaning |
|---|---|
| S1 | First-order index: fraction of output variance explained by Xi alone, ignoring all interactions. The sum of all S1 ≤ 1. |
| ST | Total-order index: fraction explained by Xi including all interactions involving Xi. ST ≥ S1 always. |
Three diagnostic rules:
- ST − S1 ≈ 0 → the parameter acts independently, no significant interactions
- ST − S1 > 0 → the parameter interacts with others; the gap quantifies the interaction share
- ST ≈ 0 → the parameter can be fixed at any value without materially affecting output variance
The Saltelli sampling scheme​
Sobol uses a specific sampling design due to Saltelli (2002). Two independent base
matrices A and B of shape (sample × k) are drawn, and k+2 derived matrices
are constructed from them. This gives a total run count of:
total runs = sample × (2k + 2)
With sample: 100 and k = 5 parameters:
100 × (2 × 5 + 2) = 100 × 12 = 1200 runs
This is significantly more expensive than Morris. For a first analysis, sample: 100
is sufficient to detect dominant parameters. For publication-quality estimates,
sample: 500 or more is recommended.
Morris vs Sobol​
| Morris | Sobol | |
|---|---|---|
| Cost | r × (k+1) | N × (2k+2) |
| Indices | μ, μ*, σ | S1, ST |
| Interactions | Detected via σ (qualitative) | Quantified via ST |
| Best for | Screening — many parameters | Quantification — fewer parameters |
The recommended workflow is to run Morris first to eliminate negligible parameters, then run Sobol on the reduced set.
The method sobol statement​
The facets are:
outputs:— list of global variables to analyse. Mandatory.sample:— N in the Saltelli scheme. Total runs = N × (2k+2). Mandatory.report:— path to the output file. Use.txtfor a human-readable report. Mandatory.results:— path to the raw CSV with one row per run. Optional but recommended.
method sobol
outputs: ["nb_recovered"]
sample: 100
report: "../results/sobol_report.txt"
results: "../results/sobol_raw.csv";
Reading the report​
Our experiment reulted in the following report :
After the run, sobol_report.txt lists S1 and ST for each parameter. A typical result
on our SIR model shows nb_agents and infection_distance with the highest ST values,
confirming the Morris ranking. Parameters with ST close to 0 — here recovery_time —
can be fixed without loss of output variability. A large ST − S1 gap for a parameter
indicates it contributes substantially through interactions.
Complete model​
model SIR
global {
int nb_agents <- 200 min: 50 max: 500;
int nb_infected_init <- 5 min: 1 max: 50;
float infection_rate <- 0.5 min: 0.0 max: 1.0;
int infection_distance <- 5 min: 1 max: 20;
int recovery_time <- 50 min: 10 max: 200;
int max_steps <- 1000;
int nb_susceptible <- 0;
int nb_infected <- 0;
int nb_recovered <- 0;
init {
create person number: nb_agents;
ask nb_infected_init among (person as list) {
status <- "infected";
infection_timer <- recovery_time;
}
}
reflex update_counts {
nb_susceptible <- person count (each.status = "susceptible");
nb_infected <- person count (each.status = "infected");
nb_recovered <- person count (each.status = "recovered");
}
reflex stop when: cycle >= max_steps or nb_infected = 0 {
do halt;
}
}
species person skills: [moving] {
string status <- "susceptible";
int infection_timer <- 0;
float speed <- 1.0;
reflex move {
do wander();
}
reflex infect when: status = "infected" {
ask (person at_distance infection_distance) where (each.status = "susceptible") {
if flip(infection_rate) {
status <- "infected";
infection_timer <- recovery_time;
}
}
infection_timer <- infection_timer - 1;
if infection_timer <= 0 {
status <- "recovered";
}
}
aspect base {
draw circle(1) at: location color:
(status = "infected") ? #red : ((status = "recovered") ? #blue : #green);
}
}
experiment SIR_gui type: gui {
parameter "Number of agents" var: nb_agents;
parameter "Initially infected" var: nb_infected_init;
parameter "Infection rate" var: infection_rate;
parameter "Infection distance" var: infection_distance;
parameter "Recovery time" var: recovery_time;
output {
display "Population" type: java2D {
species person aspect: base;
}
display "SIR Chart" type: java2D {
chart "SIR dynamics" type: series {
data "Susceptible" value: nb_susceptible color: #green;
data "Infected" value: nb_infected color: #red;
data "Recovered" value: nb_recovered color: #blue;
}
}
monitor "Susceptible" value: nb_susceptible;
monitor "Infected" value: nb_infected;
monitor "Recovered" value: nb_recovered;
monitor "Cycle" value: cycle;
}
}
// Total runs = sample × (2k + 2) = 100 × 12 = 1200 runs
experiment SIR_Sobol type: batch
repeat: 1
keep_seed: false
until: (cycle >= max_steps or nb_infected = 0) {
parameter "Number of agents" var: nb_agents min: 50 max: 500;
parameter "Initially infected" var: nb_infected_init min: 1 max: 50;
parameter "Infection rate" var: infection_rate min: 0.0 max: 1.0;
parameter "Infection distance" var: infection_distance min: 1 max: 20;
parameter "Recovery time" var: recovery_time min: 10 max: 200;
method sobol
outputs: ["nb_recovered"]
sample: 100
report: "../results/sobol_report.txt"
results: "../results/sobol_raw.csv";
}
What's next?​
Step 7 introduces Beta^d, the third and final sensitivity analysis method available in GAMA. Unlike Sobol, it does not rely on variance — it measures how much fixing a parameter shifts the entire output distribution, making it complementary to both Morris and Sobol.