Example 4: Global Sensitivity Analysis — Sobol with MPI

(GitHub link)

This notebook runs the same Sobol sensitivity analysis as ex3 but uses MPI (Message Passing Interface) for distributed execution across multiple compute nodes or cores. The simulation script is ex4_runSA_MPI.py — a plain Python file using the same ModelAnalysisContext API with parallel_method='inter-node'. The notebook launches it via %%bash and then loads results from the shared database.

Multi-task (ex3) vs MPI (ex4):

Multi-task (ex3)

MPI (ex4)

Launch

Python API

mpiexec -n N python script.py

Scope

Single machine

Multiple nodes

Setup

No extra config

Requires MPI installation

Best for

Laptops, workstations

HPC clusters

Model: asymmetric_division — stem cell division with reparameterized probabilities (prob. progenitor_2 = 1 − prob. progenitor_1).

Parameters explored:

  • cycle_duration_stem_cell — stem cell cycle duration

  • asym_div_to_prog_1_sat — saturation probability of dividing into progenitor_1

  • asym_div_to_prog_2_sat — saturation probability of dividing into progenitor_2

Run simulations via MPI

Each MPI rank picks up its share of the sample list and writes results to the shared database independently.

%%bash
mpiexec -n 8 python ex4_runSA_MPI.py
Initializing MPI job with 8 processes...
PhysiCell already exists at: PhysiCell-master
Skipping download. Use force_download=True to override.
Generated 48 samples using Sobol
Inserting parameter: cycle_duration_stem_cell with properties: {'lower_bound': 1152.0, 'upper_bound': 1728.0, 'ref_value': 1440.0, 'perturbation': None}
Inserting parameter: asym_div_to_prog_1_sat with properties: {'lower_bound': 0.0, 'upper_bound': 1.0, 'ref_value': 0.0, 'perturbation': None}
Inserting {'frac_proj1_cells': None, 'frac_proj2_cells': None, 'run_time_sec': None} QoIs into the database
Simulations completed and results stored in the database: ex4_PhysiCell_SA_MPI.db.

Load results and compute summary statistics

# Load results from the database
from uq_physicell.model_analysis import calculate_qoi_statistics
import warnings

warnings.filterwarnings('ignore')  # Suppress all warnings for cleaner output
# Load the results
db_path = "ex4_PhysiCell_SA_MPI.db"
qoi_funcs = {'frac_proj1_cells':None, 'frac_proj2_cells':None, 'run_time_sec':None}
df_qois_mean, df_qois_std, df_qois_mcse = calculate_qoi_statistics(db_path, qoi_funcs)
display(df_qois_mean)
No QoI data provided, calculating QoIs from the database...
All samples in Samples table have corresponding entries in Output table.
Extracting QoIs from DataFrame...
frac_proj1_cells_0 frac_proj2_cells_0 run_time_sec_0 time_0
SampleID
0 0.843984 0.125880 10.825394 2880.01
1 0.896023 0.073295 11.204853 2880.01
2 0.651961 0.317536 11.537088 2880.01
3 0.661141 0.309091 10.035426 2880.01
4 0.894974 0.074299 9.719086 2880.01
5 0.614583 0.354356 10.210138 2880.01
6 0.680871 0.288447 10.976077 2880.01
7 0.663192 0.306103 10.264580 2880.01
8 0.780370 0.190008 9.784336 2880.01
9 0.771402 0.197727 9.758274 2880.01
10 0.635649 0.333468 9.517483 2880.01
11 0.780147 0.189338 10.039442 2880.01
12 0.799209 0.170477 10.289918 2880.01
13 0.836292 0.134434 10.506709 2880.01
14 0.702639 0.267537 10.712825 2880.01
15 0.752590 0.217072 9.702209 2880.01
16 0.884388 0.085096 10.094876 2880.01
17 0.711582 0.258450 12.379703 2880.01
18 0.705426 0.264439 10.686780 2880.01
19 0.684894 0.285327 9.994548 2880.01
20 0.841756 0.127919 10.427948 2880.01
21 0.854501 0.115185 10.720837 2880.01
22 0.683389 0.286643 9.708683 2880.01
23 0.858560 0.110735 10.227116 2880.01
24 0.826203 0.143850 10.323526 2880.01
25 0.802217 0.168688 11.474282 2880.01
26 0.926637 0.042279 10.585155 2880.01
27 0.938957 0.030338 10.153952 2880.01
28 0.799566 0.170120 9.704243 2880.01
29 0.930822 0.037915 10.516060 2880.01
30 0.725824 0.243672 10.657874 2880.01
31 0.718596 0.250119 10.342664 2880.01
32 0.728855 0.241534 10.072137 2880.01
33 0.705235 0.264754 9.897537 2880.01
34 0.688000 0.281485 10.426809 2880.01
35 0.718530 0.250196 10.252921 2880.01
36 0.956617 0.012311 10.453640 2880.01
37 0.963972 0.006061 11.375506 2880.01
38 0.798702 0.170593 10.119175 2880.01
39 0.776225 0.193460 10.426868 2880.01
40 0.969508 0.000000 10.063891 2880.01
41 0.817536 0.151961 9.865496 2880.01
42 0.626549 0.342758 10.799564 2880.01
43 0.732264 0.237233 10.376397 2880.01
44 0.649075 0.320611 10.482474 2880.01
45 0.649115 0.320180 9.848048 2880.01
46 0.682955 0.286553 10.143365 2880.01
47 0.665809 0.303877 10.556484 2880.01

QoI over time and relative MCSE

import matplotlib.pyplot as plt
from uq_physicell.model_analysis import plot_qoi_over_time

fig, axes = plt.subplots(len(qoi_funcs.keys()), 2, figsize=(10, 4*len(qoi_funcs.keys())))
for ax_id, qoi_name in enumerate(qoi_funcs.keys()):
     # Plot QoI time series
    plot_qoi_over_time(df_qois_mean, qoi_name, axes[ax_id,0])
    axes[ax_id,0].set_title(f"QoI over Time: {qoi_name}")
    # Plot mcse
    plot_qoi_over_time(df_qois_mcse, qoi_name, axes[ax_id,1])
    axes[ax_id,1].set_title(f"Relative MCSE over Time: {qoi_name}")

# Ensure proper layout and save the figure
plt.tight_layout()  # This will automatically adjust spacing to prevent overlaps
../_images/34c21a50175f55e0c822d058d1776274d4c83895d7c75e978ff4f641bdb28b4e.png

Sobol sensitivity indices (S1 and ST)

from uq_physicell.model_analysis import get_sa_results,load_parameter_space, plot_global_sa_results

sa_method = "Sobol Sensitivity Analysis"
qoi_names = list(qoi_funcs.keys())
sa_results, qoi_time_values = get_sa_results(db_path, qoi_names, df_qois_mean, sa_method)
param_names = load_parameter_space(db_path)['ParamName'].tolist()  # Load parameter names from the database

# Plot Global SA results
fig, axes = plt.subplots(1, 3, figsize=(10, 4))
for ax_id, qoi_name in enumerate(qoi_names):
    plot_global_sa_results(param_names, sa_method, qoi_time_values, sa_results, qoi_name, 'ST' , axes[ax_id])
    axes[ax_id].set_title(f'Global SA - {qoi_name}')
    axes[ax_id].legend(loc='best')

plt.tight_layout()
Warning: Could not convert perturbation (None) to float for parameter cycle_duration_stem_cell.
Warning: Could not convert perturbation (None) to float for parameter asym_div_to_prog_1_sat.
Running sensitivity analysis with method: Sobol Sensitivity Analysis
Running Sobol Sensitivity Analysis for QoI: frac_proj1_cells and time: 2880.01
Running Sobol Sensitivity Analysis for QoI: frac_proj2_cells and time: 2880.01
Running Sobol Sensitivity Analysis for QoI: run_time_sec and time: 2880.01
../_images/2dbec4de1ae99ab76f23d29940c0b5b38ee9effa7f8c4e4fe87bb7941f81f43b.png

Next: ex5 demonstrates local sensitivity analysis using One-At-a-Time (OAT) sampling — a lighter approach for screening which parameters matter before running a full Sobol analysis.