Example 5: Local Sensitivity Analysis — One-At-a-Time (OAT) Sampling

(GitHub link)

This notebook uses OAT (One-At-a-Time) sampling to build a simulation database for local sensitivity analysis on the virus-mac-new model. OAT varies one parameter at a time around a reference point while holding all others fixed — an efficient first screen before committing to a full Sobol analysis (ex3).

What you will learn:

  • How sampler='OAT' works — perturbation values define the % deviations tested around ref_value

  • Why qois_info={} is used here (Mode B — raw MCDS stored) and when that is the right choice (see ex2)

  • How to query any QoI from a raw-MCDS database after runs complete using calculate_qoi_from_db_file

Parameters explored:

  • mac_phag_rate_infected — macrophage phagocytosis rate of infected cells

  • mac_motility_bias — macrophage chemotactic motility bias

  • epi2infected_sat — saturation of epithelial infection transition

  • epi2infected_hfm — half-maximum rate of epithelial infection transition

Storage note: qois_info={} stores the full MCDS time series per simulation (Mode B from ex2). OAT is often exploratory, so raw storage lets you compute any QoI post-hoc without re-running.

import warnings
warnings.filterwarnings('ignore')

from uq_physicell.model_analysis import ModelAnalysisContext, calculate_qoi_from_db_file

db_path = "ex5_Simulations_OAT.db"
model_config = {"ini_path": "uq_pc_struc.ini", "struc_name": "Model_struc"}

# perturbation values are % deviations applied symmetrically around ref_value
params_info = {
    "mac_phag_rate_infected": {"ref_value": 1.0,  "perturbation": [1.0, 5.0, 10.0]},
    "mac_motility_bias":      {"ref_value": 0.15, "perturbation": [1.0, 5.0, 10.0]},
    "epi2infected_sat":       {"ref_value": 0.1,  "perturbation": [1.0, 5.0, 10.0]},
    "epi2infected_hfm":       {"ref_value": 0.4,  "perturbation": [1.0, 5.0, 10.0]},
}

# Empty qois_info → Mode B: raw MCDS stored, QoIs computed post-hoc (see ex2)
qois_info = {}

Generate samples and run simulations

context = ModelAnalysisContext(db_path, model_config, "OAT", params_info, qois_info, num_workers=8)
context.generate_samples()
print(f"Generated {len(context.dic_samples)} samples using OAT")
Generated 25 samples using OAT

Run simulations

context.run()
Simulations completed and results stored in the database: ex5_Simulations_OAT.db.

Query any QoI post-hoc from the stored MCDS database

# Define any QoI — no re-simulation required because raw MCDS is in the database
qoi_funcs = {
    "mac_count":      lambda df_cell: len(df_cell[df_cell['cell_type'] == 'macrophage']),
    "infected_count": lambda df_cell: len(df_cell[df_cell['cell_type'] == 'infected epithelial']),
}
df_qois = calculate_qoi_from_db_file(db_path, qoi_funcs)
display(df_qois.head())
SampleID time ReplicateID infected_count mac_count
0 0 0.0 0 0 10
1 0 0.0 1 0 10
2 0 0.0 2 0 10
3 0 0.0 3 0 10
4 0 0.0 4 0 10

Next: ex6 uses Latin Hypercube Sampling (LHS) for a global space-filling design — all parameters vary simultaneously instead of one at a time.