Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
191 commits
Select commit Hold shift + click to select a range
eb91683
build: bump CMake abseil pin to 20260107.1 for Clang >= 21
krystophny Jun 14, 2026
a9180e0
enzyme: opt-in Clang/Enzyme build option and AD smoke test
krystophny Jun 14, 2026
14bec3e
pybind: expose the unpreconditioned internal-basis gradient
krystophny Jun 14, 2026
215e284
ideal_mhd_model: make computeMHDForces allocation-free
krystophny Jun 14, 2026
9faf398
dft_toroidal: make ForcesToFourier allocation-free
krystophny Jun 14, 2026
66664d3
enzyme: exact autodiff of the VMEC Jacobian kernel (forward vs reverse)
krystophny Jun 14, 2026
ebd1699
ideal_mhd_model: share the Jacobian kernel between solver and autodiff
krystophny Jun 14, 2026
128d8ba
ideal_mhd_model: share the metric kernel (gsqrt, guu, guv, gvv)
krystophny Jun 14, 2026
c893db1
ideal_mhd_model: share the contravariant-field kernel (bsupu, bsupv)
krystophny Jun 14, 2026
9fe801c
ideal_mhd_model: share the covariant-field kernel (bsubu, bsubv)
krystophny Jun 14, 2026
377497c
ideal_mhd_model: share the magnetic-pressure kernel
krystophny Jun 14, 2026
e2a667d
Merge branch 'allocation-free-forces' into mhdforce-kernel
krystophny Jun 14, 2026
703d3ed
ideal_mhd_model: share the MHD force-density kernel
krystophny Jun 14, 2026
dc61132
enzyme: exact Hessian of the composed local force map
krystophny Jun 14, 2026
2c5cb30
ideal_mhd_model: share the hybrid lambda-force kernel
krystophny Jun 14, 2026
27ea1d7
ideal_mhd_model: share the constraint-force kernels
krystophny Jun 14, 2026
b11d8b3
enzyme: extend the composed-force Hessian test with the lambda force
krystophny Jun 14, 2026
7310d78
apply pre-commit formatting (ruff, docformatter, clang-format)
krystophny Jun 14, 2026
1d1fedd
apply pre-commit formatting (ruff, docformatter, clang-format)
krystophny Jun 14, 2026
e7ba197
apply pre-commit formatting (ruff, docformatter, clang-format)
krystophny Jun 14, 2026
f2b548b
apply pre-commit formatting (ruff, docformatter, clang-format)
krystophny Jun 14, 2026
7803a84
apply pre-commit formatting (ruff, docformatter, clang-format)
krystophny Jun 14, 2026
43886f9
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
625a4a7
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
30398ac
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
e30e718
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
fbbf4cc
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
9d850e8
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
7441566
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
02337c5
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
486df79
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
69b0a6a
bazel: declare force-chain kernel headers in ideal_mhd_model (sandbox…
krystophny Jun 14, 2026
7ddb2a1
test: docformatter-format test_internal_gradient docstrings
krystophny Jun 14, 2026
19e27e6
ci: re-trigger (transient apt-403 on packages.microsoft.com)
krystophny Jun 14, 2026
804b792
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
5688994
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
b205eb2
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
4e76aa6
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
130fbed
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
85e8996
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
ce7129c
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
9611219
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
7ff2aef
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
84257ff
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
8875e14
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
b5481dd
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
f9875dd
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
eb2630a
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
8361dc1
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
6bd639b
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
ff4cc1b
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
1bf9270
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
1989dd0
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
ed9da6e
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
dac979b
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
acf5abb
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
3004385
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
e14a0d6
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
f1ad6d6
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
3e9a980
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
839d0fc
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
1d83409
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
cf19d83
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
c80a611
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
29fbf1d
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
8121fe3
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
6e97c3c
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
c9033dd
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
835a017
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
d875286
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
620d184
ci: skip benchmark result upload on fork PRs (token is read-only)
krystophny Jun 14, 2026
7b4f9fb
ci: build VMEC2000 from source so the compat test runs on numpy 2
krystophny Jun 14, 2026
9c57860
test: skip vmecpp-only indata fields in the VMEC2000 compat subset
krystophny Jun 14, 2026
a176970
build: pin abseil to the 20260107.1 commit hash
krystophny Jun 15, 2026
fd7915a
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
40a33c9
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
7e2c440
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
0382bb3
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
19ceafe
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
d46732c
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
33b8e2e
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
61a2e91
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
aaaa3c3
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
33f0bd7
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
50faaa1
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
79d3d34
ci: sync VMEC2000-from-source build, benchmark fork guard, abseil com…
krystophny Jun 15, 2026
f14b26c
ci: cache and pin the VMEC2000-from-source build
krystophny Jun 15, 2026
478dd82
Merge branch 'main' into enzyme-build-option
jurasic-pf Jun 15, 2026
f15d8af
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
25ac44d
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
7664f51
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
4029084
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
92edab5
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
f2adb62
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
e65e1e9
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
8a91821
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
99de0f7
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
948d4dd
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
83c1b22
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jun 15, 2026
1c5c653
ideal_mhd_model: mark Jacobian kernel buffers __restrict
krystophny Jun 16, 2026
a56edab
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
b2c143c
ideal_mhd_model: hoist ForcesToFourier scratch out of the inner loop
krystophny Jun 16, 2026
f5d72a3
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
a4ec78c
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
d809ead
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
74e4d30
ideal_mhd_model: hoist ForcesToFourier scratch out of the inner loop
krystophny Jun 16, 2026
4a0022c
ideal_mhd_model: hoist ForcesToFourier scratch out of the inner loop
krystophny Jun 16, 2026
50d3fe3
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
8ec3835
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
8f39f6c
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
39e492f
ideal_mhd_model: hoist ForcesToFourier scratch out of the inner loop
krystophny Jun 16, 2026
efe4e80
ideal_mhd_model: hoist ForcesToFourier scratch out of the inner loop
krystophny Jun 16, 2026
cac846a
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
ad02584
ideal_mhd_model: mark Jacobian metric kernel buffers __restrict
krystophny Jun 16, 2026
27d36d2
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
e1349e6
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
e94bcc9
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
4751efd
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
20be28e
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
b8b1d92
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
06b37df
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
80ba016
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
97619be
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
2243952
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
4d76ed6
Merge branch 'main' into exact-hessian-jacobian
jurasic-pf Jun 23, 2026
2a3e9e9
Merge branch 'main' into enzyme-build-option
jurasic-pf Jun 23, 2026
1f3e4a2
enzyme: run the AD smoke test through bazel instead of ctest
krystophny Jun 24, 2026
d3a9703
ci: build ClangEnzyme and run the enzyme smoke test in CI
krystophny Jun 24, 2026
dc62c55
Merge branch 'main' into enzyme-build-option
jurasic-pf Jun 24, 2026
8adeb0b
Merge branch 'main' into expose-internal-gradient
jurasic-pf Jun 24, 2026
54cf32a
Merge remote-tracking branch 'upstream/main' into build-clang21
krystophny Jun 24, 2026
417263b
Merge branch 'build-clang21' into enzyme-build-option
krystophny Jun 24, 2026
d5f0215
Merge branch 'enzyme-build-option' into exact-hessian-jacobian
krystophny Jun 24, 2026
24ece82
output_quantities: compare jcuru/jcurv at the standard tolerance
krystophny Jun 24, 2026
8c98843
Merge branch 'exact-hessian-jacobian' into metric-kernel
krystophny Jun 24, 2026
d5bbc1d
Merge branch 'metric-kernel' into bcontra-kernel
krystophny Jun 24, 2026
1325181
Merge branch 'metric-kernel' into bcontra-kernel
krystophny Jun 24, 2026
306bade
Merge branch 'bcontra-kernel' into bco-kernel
krystophny Jun 24, 2026
0478f86
Merge branch 'bco-kernel' into pressure-kernel
krystophny Jun 24, 2026
7c50747
Merge branch 'pressure-kernel' into mhdforce-kernel
krystophny Jun 24, 2026
002d79d
Merge branch 'mhdforce-kernel' into local-force-hessian
krystophny Jun 24, 2026
b3a6445
Merge branch 'local-force-hessian' into lambda-force-kernel
krystophny Jun 24, 2026
41f60c3
Merge branch 'lambda-force-kernel' into constraint-force-kernel
krystophny Jun 24, 2026
25b7f1e
Merge branch 'constraint-force-kernel' into augmented-force-hessian
krystophny Jun 24, 2026
cc9aecd
test: address review nits in test_internal_gradient
krystophny Jun 24, 2026
c8fefc2
enzyme: drop timing-dependent benchmark from local force Hessian test
krystophny Jun 27, 2026
89e4e6b
enzyme: drop timing-dependent benchmark from local force Hessian test
krystophny Jun 27, 2026
6251ad3
enzyme: drop timing-dependent benchmark from local force Hessian test
krystophny Jun 27, 2026
4be9941
enzyme: drop timing-dependent benchmark from local force Hessian test
krystophny Jun 27, 2026
d3645fb
ideal_mhd_model: drop shadowed dead scratch in toroidal force DFT
krystophny Jun 27, 2026
f2d96ea
ideal_mhd_model: drop shadowed dead scratch in toroidal force DFT
krystophny Jun 27, 2026
5b6f79d
ideal_mhd_model: drop shadowed dead scratch in toroidal force DFT
krystophny Jun 27, 2026
a236db4
ideal_mhd_model: drop shadowed dead scratch in toroidal force DFT
krystophny Jun 27, 2026
6d0ac05
ideal_mhd_model: drop shadowed dead scratch in toroidal force DFT
krystophny Jun 27, 2026
ebed746
ci: re-trigger asan (vmec_in_memory_mgrid_test jcuru was at the 1e-7 …
krystophny Jun 27, 2026
881c1ed
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
1809ea0
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
53476b6
output_quantities: compare jcuru/jcurv at a looser opt-in tolerance
krystophny Jun 16, 2026
4a320f0
Merge branch 'main' into constraint-force-kernel
jurasic-pf Jul 7, 2026
cf2712d
Merge branch 'main' into bcontra-kernel
jurasic-pf Jul 7, 2026
0a3583b
Merge branch 'main' into bcontra-kernel
jurasic-pf Jul 7, 2026
f55a9f8
Merge remote-tracking branch 'upstream/main' into bcontra-kernel
krystophny Jul 8, 2026
f85e4dc
ideal_mhd_model: include contravariant kernel header
krystophny Jul 8, 2026
3d9ab1d
Merge branch 'bcontra-kernel' into bco-kernel
krystophny Jul 8, 2026
2989f4a
Merge branch 'bco-kernel' into pressure-kernel
krystophny Jul 8, 2026
c0f7597
Merge branch 'pressure-kernel' into mhdforce-kernel
krystophny Jul 8, 2026
33460cd
Merge branch 'mhdforce-kernel' into local-force-hessian
krystophny Jul 8, 2026
823f448
Merge branch 'local-force-hessian' into lambda-force-kernel
krystophny Jul 8, 2026
7f9a160
Merge branch 'lambda-force-kernel' into constraint-force-kernel
krystophny Jul 8, 2026
b9e8129
Merge branch 'constraint-force-kernel' into augmented-force-hessian
krystophny Jul 8, 2026
7bf672b
Merge remote-tracking branch 'upstream/main' into expose-internal-gra…
krystophny Jul 8, 2026
9247a07
Merge branch 'main' into expose-internal-gradient
jurasic-pf Jul 8, 2026
5431733
Merge branch 'main' into expose-internal-gradient
jurasic-pf Jul 8, 2026
9ec6b7a
Merge upstream/main into augmented-force-hessian
krystophny Jul 8, 2026
a34d9f1
Merge augmented-force-hessian into expose-internal-gradient
krystophny Jul 8, 2026
9de6072
Merge fast_poloidal and fast_toroidal Fourier bases into one template…
CharlesCNorton Jul 8, 2026
44b41ef
Merge branch 'main' into expose-internal-gradient
jurasic-pf Jul 8, 2026
902d930
pybind: expose the unpreconditioned internal-basis gradient (#577)
krystophny Jul 8, 2026
cd3dfc2
Clean up benchmark on demandplots (#615)
jurasic-pf Jul 8, 2026
7c81177
Report less, more targeted results in FFT bench (#617)
jurasic-pf Jul 9, 2026
686bd26
Honor iteration_style=parvmec in the native solver (#612)
CharlesCNorton Jul 9, 2026
e0f1985
Abseil status handling for mgrid errors (#613)
jurasic-pf Jul 9, 2026
2449ddc
pybind: Hessian-vector product inside VMEC++ + internal Newton-Krylov…
krystophny Jul 9, 2026
b05e2da
3d external optimizer example (#618)
jurasic-pf Jul 9, 2026
4a9e717
Remove explicit test of an example script (#622)
jurasic-pf Jul 9, 2026
2e4c22d
Refactor Fourier-resolution continuation into vmecpp.run() (#619)
clazzati-pf Jul 9, 2026
271f3bf
Fix transform hot-loop regression from Eigen3 migration (#621)
jurasic-pf Jul 9, 2026
ec3ee09
Fix typos in documentation (#627)
CharlesCNorton Jul 9, 2026
4f40e83
Restore external optimizer behavioral tests (#623)
krystophny Jul 9, 2026
f0cb35a
Make raw VMEC forces history independent (#626)
krystophny Jul 10, 2026
b2bca8f
Merge remote-tracking branch 'upstream/main' into HEAD
krystophny Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions .github/actions/run-benchmarks/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ runs:
export OMP_WAIT_POLICY=passive
pytest benchmarks/test_benchmarks.py --benchmark-json=benchmark_results.json

# github-action-benchmark's "pytest" tool always plots pytest-benchmark's
# `ops` field as iter/sec, but the C++ suite emits seconds.
# We convert both to the same format, so plotting is the same.
- name: Convert Python benchmark result to seconds
shell: bash
run: |
python3 benchmarks/to_seconds_json.py pytest benchmark_results.json benchmark_results_seconds.json

- name: Store / compare Python benchmark result
# Skip the result upload/compare for fork PRs: their GITHUB_TOKEN is
# read-only, so comment-on-alert/auto-push hit 'Resource not accessible
Expand All @@ -61,8 +69,8 @@ runs:
if: ${{ inputs.auto-push == 'true' || github.event.pull_request.head.repo.full_name == github.repository }}
uses: benchmark-action/github-action-benchmark@v1.21.0
with:
tool: "pytest"
output-file-path: benchmark_results.json
tool: "customSmallerIsBetter"
output-file-path: benchmark_results_seconds.json
gh-pages-branch: benchmark-runs
benchmark-data-dir-path: benchmarks
alert-threshold: "150%"
Expand All @@ -76,7 +84,7 @@ runs:
# Builds the four benchmark cc_binary targets, runs each with
# --benchmark_format=json, and merges their output into a single
# cpp_benchmark_results.json (schema: {"context": ..., "benchmarks": [...]})
# for the store step below. Entries with "error_occurred" (e.g. an
# for the conversion step below. Entries with "error_occurred" (e.g. an
# FFT-path benchmark skipped because no FFTX codelet exists for that
# resolution) are dropped: they carry no valid timing to track.

Expand Down Expand Up @@ -142,6 +150,14 @@ runs:
f"({skipped} skipped/errored).")
PY

# github-action-benchmark's "pytest" tool always plots pytest-benchmark's
# `ops` field as iter/sec, but the C++ suite emits seconds.
# We convert both to the same format, so plotting is the same.
- name: Convert C++ benchmark result to seconds
shell: bash
run: |
python3 benchmarks/to_seconds_json.py googlecpp cpp_benchmark_results.json cpp_benchmark_results_seconds.json

- name: Store / compare C++ benchmark result
# Same fork-PR skip rationale as the Python store step above.
#
Expand All @@ -160,8 +176,8 @@ runs:
uses: benchmark-action/github-action-benchmark@v1.21.0
with:
name: "C++ Microbenchmarks"
tool: "googlecpp"
output-file-path: cpp_benchmark_results.json
tool: "customSmallerIsBetter"
output-file-path: cpp_benchmark_results_seconds.json
gh-pages-branch: benchmark-runs
benchmark-data-dir-path: benchmarks
skip-fetch-gh-pages: true
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/full_validation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Full V&V against reference VMEC

# Runs the full Verification & Validation suite from proximafusion/vmecpp-validation
# (all ~219 input configurations against reference Fortran VMEC2000), using the
# vmecpp version built from this commit rather than the version pinned on PyPI/GitHub.
# This is a lot more exhaustive (and slower) than the "short" validation that
# vmecpp-validation itself runs on its own PRs, so it is not run on every push here.
on:
workflow_dispatch:
push:
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: ${{ github.ref_name != 'main' }}

jobs:
full-validation:
name: Run full VMEC++ validation
runs-on: ubuntu-22.04
# The full parameter scan runs ~219 configurations, each computing a reference
# wout with Fortran VMEC2000 in Docker plus one with VMEC++: budget generously.
timeout-minutes: 360
steps:
- name: Check out VMEC++
uses: actions/checkout@v4
with:
path: vmecpp
lfs: true

- name: Check out vmecpp-validation
uses: actions/checkout@v4
with:
repository: proximafusion/vmecpp-validation
path: vmecpp-validation
lfs: true

- uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install required system packages for Ubuntu
run: |
sudo apt-get update && sudo apt-get install -y \
build-essential cmake libnetcdf-dev liblapack-dev liblapacke-dev libopenmpi-dev \
libomp-dev libeigen3-dev nlohmann-json3-dev libhdf5-dev

- name: Install vmecpp-validation's Python requirements
run: |
cd vmecpp-validation
# Install everything except vmecpp itself: we build and install vmecpp
# from this commit below instead of the version pinned in requirements.txt.
grep -v '^vmecpp@' requirements.txt > requirements.no-vmecpp.txt
python -m pip install -r requirements.no-vmecpp.txt

- name: Install VMEC++ from this commit
run: python -m pip install ./vmecpp

- name: Run full validation
working-directory: vmecpp-validation
run: python validate_vmec.py

- name: Upload V&V results
if: always()
uses: actions/upload-artifact@v4
with:
name: vnvresults
path: vmecpp-validation/vnvresults_*/
retention-days: 30
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

[![CI](https://github.com/proximafusion/vmecpp/actions/workflows/tests.yaml/badge.svg)](https://github.com/proximafusion/vmecpp/actions/workflows/tests.yaml)
[![C++ core tests](https://github.com/proximafusion/vmecpp/actions/workflows/test_bazel.yaml/badge.svg)](https://github.com/proximafusion/vmecpp/actions/workflows/test_bazel.yaml)
[![Full V&V against reference VMEC](https://github.com/proximafusion/vmecpp/actions/workflows/full_validation.yaml/badge.svg)](https://github.com/proximafusion/vmecpp/actions/workflows/full_validation.yaml)
[![Publish wheels to PyPI](https://github.com/proximafusion/vmecpp/actions/workflows/pypi_publish.yml/badge.svg)](https://github.com/proximafusion/vmecpp/actions/workflows/pypi_publish.yml)

VMEC++ is a Python-friendly, from-scratch reimplementation in C++ of the Variational Moments Equilibrium Code (VMEC),
Expand Down Expand Up @@ -315,6 +316,10 @@ The single-thread runtimes as well as the contents of the "wout" file produced b
The full validation test can be found at https://github.com/proximafusion/vmecpp-validation, including a set of sensible input configurations,
parameter scan values and tolerances that make the comparison pass. See that repo for more information.

This full validation (~219 input configurations) is run against every commit to `main` and can also be triggered
on demand from the [Full V&V against reference VMEC](https://github.com/proximafusion/vmecpp/actions/workflows/full_validation.yaml) workflow
(click "Run workflow"). It builds `vmecpp` from the corresponding commit rather than using the version pinned by `vmecpp-validation`.

## Differences with respect to PARVMEC/VMEC2000

VMEC++:
Expand Down
89 changes: 89 additions & 0 deletions benchmarks/to_seconds_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# SPDX-FileCopyrightText: 2024-present Proxima Fusion GmbH <info@proximafusion.com>
#
# SPDX-License-Identifier: MIT
"""Convert pytest-benchmark or Google Benchmark JSON to seconds.

github-action-benchmark's built-in "pytest" and "googlecpp" tool parsers plot whatever
value each framework happens to report natively -- pytest-benchmark's "iter/sec" and
Google Benchmark's raw per-iteration time in its own time_unit (commonly nanoseconds).
Charting those side by side, or even a single suite whose time_unit isn't fixed,
requires the reader (or the chart's JS) to know and convert between units.

This script normalizes both to plain wall-clock seconds and emits the action's generic
"customSmallerIsBetter" schema, so the chart always plots seconds and the benchmarks.js
frontend needs no unit-detection logic.
"""

import argparse
import json


def convert_pytest(data):
results = []
for bench in data["benchmarks"]:
stats = bench["stats"]
results.append(
{
"name": bench["fullname"],
"unit": "seconds",
"value": stats["mean"],
"range": f"stddev: {stats['stddev']}",
"extra": f"rounds: {stats['rounds']}",
}
)
return results


_GOOGLECPP_TIME_UNIT_TO_SECONDS = {
"s": 1.0,
"ms": 1e-3,
"us": 1e-6,
"ns": 1e-9,
}


def convert_googlecpp(data):
results = []
for bench in data["benchmarks"]:
if bench.get("error_occurred"):
continue
factor = _GOOGLECPP_TIME_UNIT_TO_SECONDS[bench["time_unit"]]
results.append(
{
"name": bench["name"],
"unit": "seconds",
"value": bench["real_time"] * factor,
"extra": (
f"iterations: {bench['iterations']}\n"
f"cpu: {bench['cpu_time'] * factor} seconds\n"
f"threads: {bench.get('threads', 1)}"
),
}
)
return results


_CONVERTERS = {
"pytest": convert_pytest,
"googlecpp": convert_googlecpp,
}


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("format", choices=sorted(_CONVERTERS))
parser.add_argument("input", help="Raw benchmark JSON produced by the tool.")
parser.add_argument("output", help="Where to write the customSmallerIsBetter JSON.")
args = parser.parse_args()

with open(args.input) as f:
data = json.load(f)

results = _CONVERTERS[args.format](data)

with open(args.output, "w") as f:
json.dump(results, f, indent=2)


if __name__ == "__main__":
main()
17 changes: 1 addition & 16 deletions docs/_static/benchmarks.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,6 @@
"#1f6feb",
];

// Parse mean duration from the extra field (e.g. "mean: 339.88 msec\nrounds: 5")
function parseMeanSeconds(bench) {
if (!bench.extra) return null;
var match = bench.extra.match(/mean:\s*([\d.]+)\s*([\w]+)/);
if (!match) return null;
var value = parseFloat(match[1]);
var unit = match[2];
if (unit === "msec") return value / 1000;
if (unit === "usec") return value / 1000000;
if (unit === "nsec") return value / 1000000000;
if (unit === "sec") return value;
return null;
}

function renderCharts(data) {
var container = document.getElementById("benchmark-charts");
if (!container) return;
Expand Down Expand Up @@ -130,8 +116,7 @@
{
label: benchName,
data: dataset.map(function (d) {
var secs = parseMeanSeconds(d.bench);
return secs !== null ? secs : 1.0 / d.bench.value;
return d.bench.value;
}),
borderColor: color,
backgroundColor: color + "30",
Expand Down
4 changes: 2 additions & 2 deletions examples/data/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Example input and output files for VMEC++

A few cases are available for testing VMCE++ and experimenting with it:
A few cases are available for testing VMEC++ and experimenting with it:

1. `cth_like_fixed_bdy.json` - Stellarator case, similar to the Compact Toroidal Hybrid ([CTH](https://www.auburn.edu/cosam/departments/physics/research/plasma_physics/compact_toroidal_hybrid/index.htm)) device
1. `input.cth_like_fixed_bdy` - Fortran namelist input file to be used with Fortran VMEC
1. `cth_like_fixed_bdy.json` - JSON input file for VMEC++, derived from `input.cth_like_fixed_bdy` using [`indata2json`](https://github.com/jonathanschilling/indata2json)
1. `wout_cth_like_fixed_bdy.nc` - NetCDF output file, produced using [`PARVMEC`](https://github.com/ORNL-Fusion/PARVMEC) from `input.cth_like_fixed_bdy`, for testing the loading of a `wout` file using VMEC++'s tooling

1. `input.nfp4_QH_warm_start` - quasi-helically example for use with SIMSOPT
1. `input.nfp4_QH_warm_start` - quasi-helical example for use with SIMSOPT

1. `solovev` - axisymmetric Tokamak case, similar to the Solov'ev equilibrium used in the [1983 Hirshman & Whitson article](https://doi.org/10.1063/1.864116)
1. `input.solovev` - Fortran namelist input file for use with Fortran VMEC
Expand Down
Loading
Loading