Skip to content

Add svZeroDTuner application#220

Open
ncdorn wants to merge 70 commits intoSimVascular:masterfrom
aabrown100-git:svZeroDTuner
Open

Add svZeroDTuner application#220
ncdorn wants to merge 70 commits intoSimVascular:masterfrom
aabrown100-git:svZeroDTuner

Conversation

@ncdorn
Copy link
Copy Markdown
Contributor

@ncdorn ncdorn commented Apr 10, 2026

Current situation

This PR adds svZeroDTuner, a new Python package and CLI for calibrating svZeroDSolver 0D models against scalar and time-series targets. It introduces a YAML-driven tuning workflow, sensitivity analysis utilities, example configurations, documentation, and test coverage. The goal with this new application is to create an intuitive and scalable workflow for deterministic optimization of 0D models. @aabrown100-git and I have been working on this after multiple requests from the lab and specifically to address #158.

Release Notes

  • added the new svzerodtuner package under applications/svZeroDTuner
  • added a CLI entry point: svzerodtuner
    • optimize / run for optimization
    • sensitivity-analysis / sensitivity for screening studies
  • added core tuning infrastructure:
    • config loading and validation
    • parameter/model access helpers
    • expression-based output extraction
    • objective evaluation for scalar and time-series targets
    • optimization wrappers for Nelder-Mead and differential_evolution methods
    • result saving, plotting, and visualization support
  • added support for:
    • target ranges and percent-based relative_bounds
    • L1 and L2 objective norms
    • parameter scaling modes (identity, log, max)
    • multiprocessing-safe optimization/sensitivity execution
  • added 3 example workflows from real research applications:
    • closed_loop_Regazzoni
    • closed_loop_Zingaro
    • right_heart_pa
  • added extensive tuner documentation
  • updated packaging/runtime dependency declarations to install the tuner CLI and its Python dependencies
  • added regression tests for config validation, parameter validation, sensitivity behavior, and package dependency declarations

Documentation

We have added extensive tuner documentation spanning tuning overview, relevant concepts, tuner configuration, examples, API and troubleshooting.

Testing

added test_svzerodtuner.py which covers svZeroDTuner I/O functions.

Code of Conduct & Contributing Guidelines

aabrown100-git and others added 30 commits February 5, 2026 22:10
…essure and tuning LV:Emax, using Nelder-Mead
…y control-c, expose more options for differential_evolution
…orks pretty well for 3 parameters and two targets
…t_all_cycles to true (makes optimization much faster)
…low initial conditions as tunable parameters, print optimization termination reason for transparency, add complex tuning task for closed loop model
…zed l2 error, remove other objective function types that weren't even implemented to begin with
… function to only penalize simulated values outside of target range.
… to optimization function, with only simple numeric coersion. Also, remove support for all algorithm except nelder-mead and differential-evolution
…early termination if objective function is zero. Use "iteration" for both differential_evolution and Nelder-Mead, don't keep track of every function evaluation for Nelder-Mead.
…ain.py to suggest Baseline, Sensitivity, then Optimize modes
…llow target file csvs for examples in git repo
aabrown100-git and others added 18 commits February 24, 2026 11:18
…th pickle-safe objective wrapper; make SV0DTuner pickle-safe for multiprocessing.
…lative_bounds'

- Updated YAML configuration files across various examples to use 'relative_bounds' instead of 'uncertainty' for defining target tolerances.
- Modified the ConfigHandler to validate the new 'relative_bounds' field and ensure compatibility with legacy 'uncertainty'.
- Adjusted the ObjectiveFunction to handle 'relative_bounds' in the computation of target ranges.
- Enhanced documentation to reflect changes in configuration schema and usage examples.
- Added new SVG diagrams to illustrate the YAML structure and workflow of svZeroDTuner.
- Created comprehensive troubleshooting and concepts documentation for better user guidance.
- Refactor command-line usage in main.py for clarity on running baseline and optimization modes.
- Update README and YAML files to reflect new command-line syntax for running baseline and optimization.
- Improve documentation in right_heart_pa example for better user guidance on running the model.
@ncdorn ncdorn requested a review from mrp089 April 10, 2026 23:21
@ncdorn ncdorn changed the title svZeroDTuner Add svZeroDTuner Apr 10, 2026
@ncdorn ncdorn changed the title Add svZeroDTuner Add svZeroDTuner CLI, examples, docs, and tests Apr 10, 2026
@ncdorn ncdorn changed the title Add svZeroDTuner CLI, examples, docs, and tests Add svZeroDTuner application Apr 10, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces svZeroDTuner, a new Python package and CLI intended to provide a YAML-driven workflow for calibrating svZeroDSolver 0D models against scalar and time-series targets, along with sensitivity screening utilities, documentation, examples, and regression tests.

Changes:

  • Adds the svzerodtuner Python package (optimization/sensitivity orchestration, config/parameter handling, expressions/objectives, plotting/reporting).
  • Registers a new CLI entry point (svzerodtuner) and updates runtime dependencies.
  • Adds extensive documentation pages plus multiple real-world example workflows (configs, scripts, target CSVs).

Reviewed changes

Copilot reviewed 62 out of 63 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
tests/test_svzerodtuner.py Adds regression tests for tuner dependency declarations, config validation, parameter validation, and sensitivity behaviors.
setup.cfg Declares the new package, installs tuner runtime deps, and adds the svzerodtuner console script entry point.
docs/pages/tuner.md Adds the main svZeroDTuner user guide page.
docs/pages/tuner_api.md Documents CLI commands and Python APIs exposed by the tuner package.
docs/pages/tuner_concepts.md Explains tuning concepts (targets, ranges, norms, bounds/scaling, failure modes).
docs/pages/tuner_configuration.md Defines YAML schemas and validation rules for optimization and sensitivity configs.
docs/pages/tuner_examples.md Provides worked example workflows and expected outputs.
docs/pages/tuner_troubleshooting.md Adds troubleshooting guidance for common tuning issues.
docs/pages/main.md Links svZeroDTuner guide from docs main page.
docs/pages/developer_guide.md Adds svZeroDTuner references into the developer guide docs navigation.
applications/svZeroDTuner/svzerodtuner/init.py Defines the package and its version.
applications/svZeroDTuner/svzerodtuner/cli.py Implements svzerodtuner CLI command parsing and dispatch.
applications/svZeroDTuner/svzerodtuner/config_handler.py Adds YAML loading, path resolution, and validation for optimization configs.
applications/svZeroDTuner/svzerodtuner/expression_handler.py Adds expression compilation/evaluation for extracting outputs and defining targets/QoIs.
applications/svZeroDTuner/svzerodtuner/objective.py Implements range-based objective computation for scalar and time-series targets.
applications/svZeroDTuner/svzerodtuner/optimizer.py Wraps SciPy optimizers (Nelder-Mead / differential evolution), history, scaling, callbacks, and early termination.
applications/svZeroDTuner/svzerodtuner/output_extractor.py Provides helpers for extracting solver outputs by exact result names.
applications/svZeroDTuner/svzerodtuner/parameter_handler.py Implements model parameter get/set by Block.Parameter naming.
applications/svZeroDTuner/svzerodtuner/result_handler.py Saves histories/results and generates summary outputs/plots.
applications/svZeroDTuner/svzerodtuner/scaling.py Adds parameter scaling transforms between physical and optimizer spaces.
applications/svZeroDTuner/svzerodtuner/sensitivity.py Implements correlation-based screening using Sobol sampling and reporting/visualization.
applications/svZeroDTuner/svzerodtuner/simulation.py Centralizes simulation execution used by both optimization and sensitivity flows.
applications/svZeroDTuner/svzerodtuner/sv0d_tuner.py Orchestrates end-to-end optimization runs, objective evaluation, result saving, and reporting.
applications/svZeroDTuner/svzerodtuner/visualization.py Adds plotting utilities for history, parameters, targets, and full simulation outputs.
applications/svZeroDTuner/requirements.txt Provides a tuner-specific requirements list for example usage.
applications/svZeroDTuner/.gitignore Ignores generated tuner example artifacts (baseline/results folders).
applications/svZeroDTuner/examples/right_heart_pa/README.md Documents the right-heart/pulmonary-artery tuning example workflow.
applications/svZeroDTuner/examples/right_heart_pa/main.py Adds baseline/optimize/sensitivity driver script for the right_heart_pa example.
applications/svZeroDTuner/examples/right_heart_pa/tuning_differential_evolution.yaml Differential evolution tuning config for right_heart_pa example.
applications/svZeroDTuner/examples/right_heart_pa/tuning_nelder_mead.yaml Nelder-Mead tuning config for right_heart_pa example.
applications/svZeroDTuner/examples/closed_loop_Zingaro/main.py Adds baseline/optimize/sensitivity driver script for the Zingaro closed-loop example.
applications/svZeroDTuner/examples/closed_loop_Zingaro/model.json Adds the closed-loop Zingaro example model JSON.
applications/svZeroDTuner/examples/closed_loop_Zingaro/sensitivity.yaml Sensitivity screening config for the Zingaro example.
applications/svZeroDTuner/examples/closed_loop_Zingaro/tuning.yaml Optimization config for the Zingaro example.
applications/svZeroDTuner/examples/closed_loop_Zingaro/tuning_job.sh Adds an HPC batch script template for running tuning on a cluster.
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/convert_volume_data.py Utility to convert volume CSVs to tuner target CSV format.
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/la_volume_manual.csv Adds LA volume reference data (manual).
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/target_V_LA.csv Adds time-series target for LA volume.
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/target_V_LV.csv Adds time-series target for LV volume.
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/target_V_RA.csv Adds time-series target for RA volume.
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/target_V_RV.csv Adds time-series target for RV volume.
applications/svZeroDTuner/examples/closed_loop_Zingaro/targets/P003_chamber_volumes/volume.csv Adds source volume dataset used by conversion utility.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/main.py Adds baseline/optimize/sensitivity driver script for the Regazzoni closed-loop example.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/model.json Adds the closed-loop Regazzoni example model JSON.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/sensitivity.yaml Sensitivity screening config for the Regazzoni example.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/tuning_complex.yaml More comprehensive optimization config for the Regazzoni example.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/tuning_differential_evolution.yaml Differential evolution tuning config for the Regazzoni example.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/tuning_job.sh Adds an HPC batch script template for running tuning on a cluster.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/tuning_nelder_mead.yaml Nelder-Mead tuning config for the Regazzoni example.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/tuning_time_series_target.yaml Demonstrates a time-series target matching configuration.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/create_target_from_baseline.py Utility to create time-series targets from baseline results.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/target_pressure_ar_sys.csv Example time-series target CSV for arterial pressure.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/convert_volume_data.py Utility to convert chamber volume data to tuner target CSV format.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/la_volume_manual.csv Adds LA volume reference data (manual).
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/target_V_LA.csv Adds time-series target for LA volume.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/target_V_LV.csv Adds time-series target for LV volume.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/target_V_RA.csv Adds time-series target for RA volume.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/target_V_RV.csv Adds time-series target for RV volume.
applications/svZeroDTuner/examples/closed_loop_Regazzoni/targets/P003_chamber_volumes/volume.csv Adds source volume dataset used by conversion utility.
README.md Adds a documentation link to the tuner guide and removes CI/coverage badges.
.gitignore Un-ignores target CSVs under tuner examples while keeping global CSV ignore.
.github/workflows/test.yml Adjusts Windows CI Python deps to include PyYAML (for tuner configs).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread setup.cfg
svzerodtuner
package_dir =
svzerodtuner = applications/svZeroDTuner/svzerodtuner
python_requires = >=3.0
shell: pwsh
run: |
python -m pip install --upgrade cmake cmake-setuptools numpy ninja pytest pandas graphviz networkx pydot
python -m pip install --upgrade cmake cmake-setuptools numpy ninja pytest pandas graphviz networkx pydot pyyaml
Comment on lines +59 to +62
lo, hi = float(bounds[0]), float(bounds[1])
self._max_bound = max(lo, hi)
if self._max_bound == 0:
raise ValueError("Max scaling requires non-zero bounds")
Comment on lines +180 to +182
try:
analyzer.run_analysis()
except Exception as e:
Comment on lines +121 to +125
try:
pct = float(unc.strip()[:-1])
if pct < 0:
raise ValueError(
f"Target '{target['name']}' relative_bounds percent must be non-negative"
"<expr>",
"exec",
)
exec(code, namespace)
Comment on lines +237 to +240
except Exception as e:
# Return large value if simulation fails
print(f"Warning: Simulation failed: {e}")
return float(1e10)
Comment on lines +553 to +556
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Agg')
except ImportError:
Comment thread README.md
Comment on lines 4 to 6

[![Test Status](https://github.com/simvascular/svZeroDSolver/actions/workflows/test.yml/badge.svg)](https://github.com/simvascular/svZeroDSolver/actions)
[![codecov](https://codecov.io/gh/SimVascular/svZeroDSolver/graph/badge.svg?token=FQKC9L5I0W)](https://codecov.io/gh/SimVascular/svZeroDSolver)
[![Latest Release](https://img.shields.io/github/v/release/simvascular/svZeroDSolver?label=latest)](https://github.com/simvascular/svZeroDSolver/releases/latest)
![Platform](https://img.shields.io/badge/platform-macOS%20|%20Ubuntu-blue)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave the badges?

Comment on lines +30 to +34
# Send an email to this address when your job starts and finishes
#SBATCH --mail-user=abrown97@stanford.edu
#SBATCH --mail-type=begin
#SBATCH --mail-type=fail
#SBATCH --mail-type=end
Copy link
Copy Markdown
Member

@mrp089 mrp089 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice application! I had some ideas for the documentation and examples.

Comment thread docs/pages/tuner.md
- Post-processing and network inspection (use [svZeroDVisualization](@ref visualization))
- Fundamental model-structure changes (update the model itself first)

# Quickstart
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many helpful sub-pages are listed under Related Tools, which can make it hard to find. Link these more visibly at the top.

Comment thread README.md
Comment on lines 4 to 6

[![Test Status](https://github.com/simvascular/svZeroDSolver/actions/workflows/test.yml/badge.svg)](https://github.com/simvascular/svZeroDSolver/actions)
[![codecov](https://codecov.io/gh/SimVascular/svZeroDSolver/graph/badge.svg?token=FQKC9L5I0W)](https://codecov.io/gh/SimVascular/svZeroDSolver)
[![Latest Release](https://img.shields.io/github/v/release/simvascular/svZeroDSolver?label=latest)](https://github.com/simvascular/svZeroDSolver/releases/latest)
![Platform](https://img.shields.io/badge/platform-macOS%20|%20Ubuntu-blue)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave the badges?

Comment thread docs/pages/tuner.md
Run optimization:

```bash
svzerodtuner optimize applications/svZeroDTuner/examples/right_heart_pa/tuning_differential_evolution.yaml
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example takes a long time to run (107 iterations with 55,314 function evals). Is this setup correct? Is there a more straightforward first example users can run? Is this a synthetic example where we should recover the exact parameters (and do we)?

Comment thread docs/pages/tuner.md

## CLI workflow

Run optimization:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be helpful to showcase some useful outputs users can expect, maybe in individual example readmes, and link them here.

Comment thread docs/pages/tuner.md
Run sensitivity analysis:

```bash
svzerodtuner sensitivity-analysis applications/svZeroDTuner/examples/closed_loop_Regazzoni/sensitivity.yaml
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, what is computed here, what output do we get, does it make sense?

Comment thread docs/pages/tuner.md

# Workflow

A typical svZeroDTuner workflow is:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do the tools optimize and sensitivity tie in here?


# Convergence and Termination

svZeroDTuner currently supports:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only those two? Can you link to the scipy functions this is built on?

- `differential_evolution`
- `Nelder-Mead`

Optimization options are passed through to SciPy using native option names.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you say something about those two optimization methods and when to use them?


[TOC]

# What Is Being Tuned
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide some fundamental math of what's being solved using arg min, etc.?

@@ -0,0 +1,71 @@
@page tuner_concepts svZeroDTuner Concepts
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find anything behind the math for the sensitivity analysis. What is being computed? What do the sensitivity values mean? Is there a literature reference?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants