Skip to content

Running physverify in CI

A spec file can run on every push, so that a change which breaks the physics fails the build the same way a broken unit test does. This page covers starting a spec (physverify init), the GitHub Action, pre-commit, and plain pytest.

1. Start a spec

For a fixed-step ODE solver:

physverify init verify_solver.py --solver mysolver --function integrate --dim 2 --order 4

This writes verify_solver.py. It needs two things from you, both marked TODO:

  • reference_rhs(t, y): the equations the solver is meant to solve, written from the physics, not copied from the solver. A copied mistake passes every check.
  • Y0: a typical initial state.

The solver function must have the form integrate(source, y0, t_end, n_steps), take fixed steps from t = 0, and add source(t) to the right-hand side wherever it evaluates it. If it has no such hook, write a small wrapper in the spec that adds one (see benchmark/pvbench/adapters/projectile_v2.py).

The spec checks the claimed order with a manufactured solution and against an independent solution of reference_rhs, and runs the exactness (patch) check, which holds for explicit Runge-Kutta methods; remove that check for other kinds of stepper. Until reference_rhs is written, every check reports ERROR.

For PDE codes, Monte Carlo codes and Runge-Kutta tables there is no template yet; start from the examples in examples/ and docs/technical.md.

2. GitHub Actions

# .github/workflows/physverify.yml
name: physverify
on: [push, pull_request]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: rcgiri-physics/physverify@v0.5.1
        with:
          specs: tests/verify_*.py   # default: **/verify_*.py
          install: -e .              # your package and its dependencies

Which tag to use: @v0.5.1 runs exactly that version until you change it. @v0 always runs the newest 0.x release, so you get fixes (and new checks, which can turn a passing job red) without editing the workflow.

The job fails when any check is not PASS or EXACT, or when no spec matches. The result table appears on the run's summary page, and an HTML report with convergence plots is uploaded as an artifact.

Inputs:

Input Default Meaning
specs **/verify_*.py Spec files or glob patterns, separated by spaces.
install empty Arguments for pip install for your own code, for example -e . or -r requirements.txt.
python-version 3.12 Python to set up. Empty uses the Python already on the runner, for example one your job set up with its own dependencies.
version empty physverify version from PyPI. Empty installs the copy at the action's ref, so @v0.5.1 runs physverify 0.5.1.
working-directory . Folder to run in.
html-report physverify-report Name of the uploaded HTML report. Empty uploads nothing.

The output json is the path of the JSON results file, for a later step that wants the numbers.

If your job already sets up an environment (conda, a compiled extension), set python-version: "" and run the action after that set-up. Or skip the action and run the command yourself:

      - run: pip install physverify
      - run: physverify run "tests/verify_*.py" --markdown "$GITHUB_STEP_SUMMARY" --html physverify.html

3. pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/rcgiri-physics/physverify
    rev: v0.5.1
    hooks:
      - id: physverify
        args: ["tests/verify_*.py"]
        additional_dependencies: [scipy]   # whatever your solver imports besides NumPy

pre-commit runs hooks in their own environment, so your solver's dependencies must be listed in additional_dependencies. The hook runs on every commit that changes a Python file, because a change to the solver matters as much as a change to the spec.

4. pytest

With physverify installed, pytest collects the checks in verify_*.py files as tests, so an existing pytest job runs them with no change:

pytest tests/verify_solver.py

Command-line options used in CI

  • physverify run exits 0 when every check passes, 1 when any does not, and 2 when a spec cannot be loaded or a pattern matches nothing.
  • Glob patterns are expanded by physverify, so "**/verify_*.py" works the same in bash, PowerShell and cmd.
  • --markdown FILE appends a result table to FILE; --json FILE and --html FILE write the other formats.