{ "cells": [ { "cell_type": "markdown", "id": "de5fa857", "metadata": {}, "source": [ "# Example 1: Context Setup and Internals — Educational Walkthrough\n", "\n", "[(GitHub link)](https://github.com/heberlr/UQ_PhysiCell/tree/main/examples/ex1_context_setup.ipynb)\n", "\n", "This notebook walks through `ModelAnalysisContext` step by step with verbose logging, so you can see exactly what the library configures internally before and during a simulation run. It mirrors the same API used in ex2 and ex3+ — the only difference is the inspection of context internals between steps.\n", "\n", "**What you will learn:**\n", "- How `params_info` and `qois_info` are stored and serialized inside the context\n", "- How the QoI lambda dispatch works (what `df_cell`, `df_subs`, `mcds` mean)\n", "- What `context.run()` does internally, step by step — revealed by the INFO log output\n", "\n", "> The INFO log emitted by `context.run()` includes the full PhysiCell model configuration (equivalent to what the old `PhysiCell_Model.info()` call showed), database operations, and per-simulation progress." ] }, { "cell_type": "code", "execution_count": 1, "id": "f4bb950e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PhysiCell already exists at: PhysiCell-master\n", "Skipping download. Use force_download=True to override.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import logging, sys\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "# Verbose logging — context.run() emits INFO messages at every internal step\n", "logging.basicConfig(\n", " stream=sys.stdout,\n", " level=logging.INFO,\n", " format='[%(levelname)s] %(message)s',\n", " force=True,\n", ")\n", "\n", "from uq_physicell import get_physicell\n", "from uq_physicell.model_analysis import ModelAnalysisContext\n", "\n", "get_physicell(target_dir=\".\")" ] }, { "cell_type": "markdown", "id": "b274a5b2", "metadata": {}, "source": [ "## Step 1 — Build the context and inspect its internals\n", "\n", "`model_config` points to the INI file and selects the model structure. \n", "`params_info` declares parameter metadata stored in the database. **What fields are needed depends on the sampler:**\n", "\n", "| Sampler | Required fields | Optional metadata |\n", "|---|---|---|\n", "| `Sobol`, `LHS`, `FAST`, `FF` | `lower_bound`, `upper_bound` | `ref_value` |\n", "| `OAT` | `ref_value`, `perturbation` | — |\n", "| `User-defined` | none (samples from `set_samples()`) | `ref_value` |\n", "\n", "`qois_info` defines what to measure — **the lambda parameter name controls what PhysiCell data is passed:**\n", "\n", "| Parameter name | Data received |\n", "|---|---|\n", "| `df_cell` or `df` | `pandas.DataFrame` — one row per cell at each timestep |\n", "| `df_subs` | `pandas.DataFrame` — substrate concentrations on the mesh |\n", "| `mcds` | `pcdl.TimeStep` — full snapshot object |\n", "| `mcds_ts` | `list[pcdl.TimeStep]` — full time series (evaluated once, at last step) |\n", "\n", "After creating the context, we inspect `context.qois_dict` to see how lambdas are converted to strings — this serialization is what allows QoI functions to be sent across processes in parallel execution." ] }, { "cell_type": "code", "execution_count": 2, "id": "40b5a4db", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "params_dict (parameter space as stored in context):\n", " viral_replication_rate: {'ref_value': 0.125}\n", " min_virion_count: {'ref_value': 1.0}\n", "\n", "qois_dict (lambdas serialized to strings for multiprocessing):\n", " 'live_cells': \"lambda df_cell: len(df_cell[df_cell['dead'] == False])\"\n", " 'dead_cells': \"lambda df_cell: len(df_cell[df_cell['dead'] == True])\"\n", " 'interferon_mean': \"lambda df_subs: df_subs['interferon'].mean()\"\n", "\n", "metadata:\n", " Sampler: User-defined\n", " IniFilePath: Model_Struct.ini\n", " StrucName: physicell_model_2\n" ] } ], "source": [ "model_config = {\"ini_path\": \"Model_Struct.ini\", \"struc_name\": \"physicell_model_2\"}\n", "\n", "# For 'User-defined' sampler, params_info is optional metadata stored in the DB.\n", "# Bounds and perturbations are not needed — samples come from set_samples().\n", "# Only ref_value is useful here as a reference point for comparison.\n", "params_info = {\n", " \"viral_replication_rate\": {\"ref_value\": 0.125},\n", " \"min_virion_count\": {\"ref_value\": 1.0},\n", "}\n", "\n", "qoi_funcs = {\n", " \"live_cells\": lambda df_cell: len(df_cell[df_cell['dead'] == False]),\n", " \"dead_cells\": lambda df_cell: len(df_cell[df_cell['dead'] == True]),\n", " \"interferon_mean\": lambda df_subs: df_subs['interferon'].mean(),\n", "}\n", "\n", "context = ModelAnalysisContext(\n", " \"ex1_inspect.db\", model_config,\n", " sampler='User-defined',\n", " params_info=params_info,\n", " qois_info=qoi_funcs,\n", " num_workers=1,\n", ")\n", "\n", "# ── Inspect context internals ────────────────────────────────────────────────\n", "print(\"params_dict (parameter space as stored in context):\")\n", "for name, props in context.params_dict.items():\n", " print(f\" {name}: {props}\")\n", "\n", "print(\"\\nqois_dict (lambdas serialized to strings for multiprocessing):\")\n", "for name, func_str in context.qois_dict.items():\n", " print(f\" {name!r}: {func_str!r}\")\n", "\n", "print(\"\\nmetadata:\")\n", "for k, v in context.dic_metadata.items():\n", " print(f\" {k}: {v}\")" ] }, { "cell_type": "markdown", "id": "c7122467", "metadata": {}, "source": [ "## Step 2 — Provide a sample and run\n", "\n", "We pass a single reference point so the simulation finishes quickly. The `[INFO]` output from `context.run()` reveals every internal step in order:\n", "\n", "1. **PhysiCell model info** — executable path, parameters in XML, replicate count (same output as the old `PhysiCell_Model.info()`)\n", "2. **Database setup** — creates tables, inserts metadata, parameter space, and QoI definitions\n", "3. **Simulation progress** — one line per completed replicate with data size written to the database" ] }, { "cell_type": "code", "execution_count": 3, "id": "a7dbd4b3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "dic_samples: {0: {'viral_replication_rate': 0.125, 'min_virion_count': 1.0}}\n", "\n", "[INFO] PhysiCell Model Information:\n", "Project name: Template \n", " Executable: PhysiCell-master/virus-sample\n", " Number of replicates for each parameter set: 5 \n", " Config. file of reference: PhysiCell-master/sample_projects/virus_macrophage/config/PhysiCell_settings.xml\n", " Folder to save config. files: UQ_PC_InputFolder/ \n", " Folder to save output folders: UQ_PC_OutputFolder/\n", " Rules file of reference: None\n", " Name of output folders: output_S%06d_R%03d/\n", " Number of omp threads for each simulation: 4\n", " Number of parameters for sampling in XML: 2\n", " Parameters in XML: ['viral_replication_rate', 'min_virion_count']\n", " Number of parameters for sampling in RULES: 0\n", " Parameters in RULES: []\n", "[INFO] Creating database structure in ex1_inspect.db\n", "[INFO] Inserting metadata, parameter space, and QoIs into the database\n", "Inserting parameter: viral_replication_rate with properties: {'ref_value': 0.125}\n", "Inserting parameter: min_virion_count with properties: {'ref_value': 1.0}\n", "Inserting {'live_cells': \"lambda df_cell: len(df_cell[df_cell['dead'] == False])\", 'dead_cells': \"lambda df_cell: len(df_cell[df_cell['dead'] == True])\", 'interferon_mean': \"lambda df_subs: df_subs['interferon'].mean()\"} QoIs into the database\n", "[INFO] Inserting samples into the database\n", "[INFO] Generating 5 simulations\n", "[INFO] Writing to the database for Sample: 0, Replicate: 0, Result size: 1.49 KB\n", "[INFO] Writing to the database for Sample: 0, Replicate: 1, Result size: 1.49 KB\n", "[INFO] Writing to the database for Sample: 0, Replicate: 2, Result size: 1.49 KB\n", "[INFO] Writing to the database for Sample: 0, Replicate: 3, Result size: 1.49 KB\n", "[INFO] Writing to the database for Sample: 0, Replicate: 4, Result size: 1.49 KB\n", "Simulations completed and results stored in the database: ex1_inspect.db.\n" ] } ], "source": [ "context.set_samples([\n", " {\"viral_replication_rate\": 0.125, \"min_virion_count\": 1.0}, # reference point\n", "])\n", "\n", "print(f\"dic_samples: {context.dic_samples}\\n\")\n", "context.run()" ] } ], "metadata": { "kernelspec": { "display_name": "pcvenv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }