This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
5. Morris Sensitivity Analysis
Now that we know how much stochasticity contributes to output variability, we can apply
the first sensitivity analysis method: Morris. This method screens parameters by
their influence on nb_recovered and is the recommended starting point before the more
expensive Sobol analysis — it gives qualitative rankings at a fraction of the cost.
In particular, this step presents:
- The principle of the Morris method and its three indices μ, μ* and σ
- How to declare
method morrisand configure its key facets - How to read and interpret the report file produced by GAMA
- The computational cost of the method and how to tune it
The model file for this step can be found in:
Library models/Tutorials/SIRAnalysis/models/SIR_Morris.gaml
How Morris works
Morris is a One-At-a-Time (OAT) screening method. It samples r random starting
points (trajectories) in the parameter space and, from each, changes one parameter at a
time while holding all others fixed. The change in output caused by each step is called
an elementary effect. After r trajectories, three summary statistics are computed
for each parameter:
| Index | Meaning |
|---|---|
| μ (mu) | Mean of elementary effects — signed average influence. Can cancel if effects are of opposite sign across the space. |
| μ* (mu_star) | Mean of absolute elementary effects — the main ranking index, robust to non-monotonic models. |
| σ (sigma) | Standard deviation of elementary effects — captures non-linearity and interactions with other parameters. |
The μ* vs σ plane is the standard diagnostic plot for Morris results:
| μ* | σ | Interpretation |
|---|---|---|
| High | Low | Strong, approximately linear effect |
| High | High | Strong effect with interactions or non-linearities |
| Low | Low | Negligible parameter — can be fixed |
| Low | High | Influential only through interactions |
Total run count
For r trajectories and k parameters, Morris requires exactly r × (k + 1)
simulation runs. With sample: 10 and k = 5 parameters:
10 × (5 + 1) = 60 runs
Increasing sample improves the robustness of the indices but scales linearly with
cost. A value of 10–20 trajectories is standard for a first screening.
The method morris statement
The facets are:
outputs:— list of global variables to use as sensitivity targets. 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.levels:— number of grid levels for the OAT design. The default value of 4 is appropriate for most models. Must be even.sample:— number of trajectories r. More trajectories give more stable estimates.
Reading the report
After the run, morris_report.txt contains one block per output variable listing μ,
μ* and σ for each parameter. Here is an example obtained on our SIR model:
Reading by μ* rank: nb_agents and infection_rate dominate, followed at a
distance by infection_distance and recovery_rate. nb_infected_init has negligible
direct influence. The high σ of infection_rate relative to its μ* suggests it acts
mainly through interactions rather than as a direct driver.
The morris_rax.csv contains the sampling strategy used by the experiment.
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 × (k + 1) = 10 × 6 = 60 runs
experiment SIR_Morris 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 morris
outputs: ["nb_recovered"]
report: "../results/morris_report.txt"
results: "../results/morris_raw.csv"
levels: 4
sample: 10;
}
What's next?
Morris gives qualitative rankings. Step 6 introduces Sobol, which goes further by quantifying exactly how much of the output variance each parameter explains — both directly (S1) and through interactions (ST).
Home
Platform
- Installation and Launching
- Workspace, Projects and Models
- Editing Models
- Running Experiments
- Running Headless
- Preferences
- Troubleshooting
Learn GAML step by step
- Introduction
- Manipulate basic Species
- Global Species
- Defining Advanced Species
- Defining GUI Experiment
- Exploring Models
- Optimizing Models
- Multi-Paradigm Modeling
Recipes
- Manipulate OSM Data
- Cleaning OSM Data
- Diffusion
- Using Database
- Using FIPA ACL
- Using BDI with BEN
- Using Driving Skill
- Manipulate dates
- Manipulate lights
- Using comodel
- Save and restore Simulations
- Using network
- Headless mode
- Using Headless
- Writing Unit Tests
- Ensure model's reproducibility
- Going further with extensions
GAML References
- Built-in Species
- Built-in Skills
- Built-in Architecture
- Statements
- Data Type
- File Type
- Expressions
- Exhaustive list of GAMA Keywords
Developing GAMA
- Installing the development version
- Developing Extensions
- Introduction to GAMA Java API
- Using GAMA flags
- Creating a release of GAMA
- Documentation generation