5 SIRAnalysis_step5
BenjaminPianet edited this page 2026-04-11 20:39:08 +07:00
This file contains ambiguous Unicode characters

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 morris and 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 1020 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 .txt for 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:

Morris Report

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).