Added
-
AMR checkpoint/restart (ADC-65):
AmrSystem.checkpoint(path)/restart(path)write and read
a bit-identical npz (per-level conservative state with fine patches, per-level phi as the multigrid
warm-start, the fine hierarchy and the clock), replacing the oldNotImplementedError. Restart
imposes the saved fine layout via the newset_hierarchy(no re-clustering, no re-prolongation).
Mono-block mono-rank for now: MPI np>1, multi-block andregrid_every>0are rejected explicitly.
Adds the append-only level accessorsn_levels/n_vars/level_state/level_potential/
set_hierarchy. -
Model-declared named aux fields (ADC-70, phase 1, Cartesian
System): a model declares
persistent auxiliary fields withm.aux_field("name")(read in a formula viaaux.extra_field(k));
sim.set_aux_field(block, name, array)andsim.aux_field(block, name)set and read them (up to
four). TheAuxPOD stays trivially copyable and device-clean, named components are static (never
rewritten bysolve_fields), and a model with no named field is cache/hash-identical to before;
B_z/T_estay on their dedicated setters. -
Generic 2D moment-hierarchy generator (ADC-164): the new
adc.momentsmodule derives the full
M->C->S->closure->C'->M' algebra (binomial transform plus standardization) over the DSL AST, so a
user supplies only the closure (S -> standardized moments of order N+1). Shipsbuild_moment_model,
gaussian_closure(Levermore),lorentz_sources(Vlasov-Lorentz) andmoment_indices/
moment_names;robust=Trueadds differentiable smooth floors andexact_speeds=Truewires HLL
speeds via autodiff plus numeric eig. -
SSPRK3 time integration on AMR (ADC-64):
AmrSystem.add_block(..., time="ssprk3")(or
adc.Explicit(ssprk3=True)) runs a 3-stage Shu-Osher SSPRK3 per subcycled level, staying exactly
conservative across coarse-fine boundaries by refluxing the effective flux
Feff = 1/6 F0 + 1/6 F1 + 2/3 F2. The default stays forward Euler (bit-identical); rejected
explicitly on the compiled.sopaths and withimex. -
First-order forward Euler explicit method (ADC-174):
adc.Explicit(method="euler")selects the
ForwardEulerstepper onSystem.add_block(native andbackend="production"), for
first-order-reference fidelity;ssprk2stays the default. The frozen-ABI AOT path rejectseuler
(pointing to the production/native backends) rather than silently ignoring it. -
Explicit signed wave speeds in the DSL (ADC-83):
m.wave_speeds(x=(smin,smax), y=(smin,smax))
declares signed face speeds directly, unlockingriemann="hll"for models with no pressure
primitive (moment systems, isothermal). Withoutset_eigenvaluesthe Rusanov/CFL bound derives
frommax(|smin|,|smax|); anadd_equationguard rejectsriemann="hll"with no emitted speeds. -
HLL wave speeds from the flux Jacobian (ADC-86/87):
m.wave_speeds_from_jacobian(x=, y=, eig="numeric"|"fd", blocks=)emits exact HLL speeds as the spectrum extremes of the flux Jacobian
(new device-clean headeradc::real_eig_minmax: closed form for N<=2, Hessenberg plus Francis QR
otherwise, Gershgorin outer-bound fallback).x/y=Noneautodiffs the declared flux; theAbs
autodiff node is now differentiable, so smoothmax(x,eps)floors are Jacobian-able. -
Positivity floor limiter (ADC-76):
adc.FiniteVolume(positivity_floor=...)imposes a density
floor on reconstructed face states, falling back locally to the source-cell average (conservative,
first-order) on a violating face.floor<=0is bit-identical to before; it is threaded through the
Cartesian, polar and cut-cell kernels and the compiled-block ABI, and rejected explicitly on the
paths that do not support it (prototype JIT, AOT/production, AMR). -
Opt-in HLL wave-speed cache (ADC-199):
adc.FiniteVolume(wave_speed_cache=True)evaluates
model.wave_speedsonce per cell and direction and reuses it as the face bound instead of
recomputing on every face and RK stage (measured speedup on moment hierarchies). Off by default,
bit-identical to OFF in the no-slope path, and rejected outsideriemann="hll"plus explicit time. -
Spectral Poisson FFT variant (ADC-175): a new elliptic kind
solver="fft_spectral"(from
System.set_poisson,adc.EllipticSolver, listed inadc.capabilities()) reuses the periodic
single-rank FFT plumbing of"fft"but with the continuous Laplacian symbol-(kx^2+ky^2), exact
on sinusoids. The discrete"fft"and"geometric_mg"solvers are unchanged. -
Native Windows (MSVC) support (ADC-99/100/136/144):
adc_cppcompiles and imports natively on
Windows without WSL2. A portable dynamic-loading layeradc::dynlib(LoadLibraryW/
GetProcAddress), anADC_EXPORTmacro (__declspec), an MSVC-aware ABI key, and
std::numbers::piforM_PIcover the runtime; the DSLproductionbackend compiles a model to a
.dllwithcland runs bit-identical to the brick path (shared Kokkos,_adc.lib). All_WIN32
branches are dead off Windows. -
System.dt_hotspot(name)CFL diagnostic (ADC-182): returns{w, i, j}for the global cell
that dominates a block's transport CFL bound, to locate a collapsing dt without an external scan.
On-demand and off the hot path (step/step_cflstay bit-identical), a two-pass device-clean
reduction with an MPI all-reduce. -
Find-or-fetch Kokkos (ADC-263): if no Kokkos install is found, CMake downloads and builds a
release tarball verified by SHA256, so a plaincmake -B buildworks without a pre-installed
Kokkos. Overridable viaADC_KOKKOS_FETCH_VERSION(default 4.4.01) andADC_KOKKOS_FETCH_SHA256. -
Eigenvalue witness in the projection DSL (ADC-289):
dsl.eig_max_im(rows),dsl.eig_lmin(rows)
anddsl.eig_lmax(rows)build a small dense matrix from moment expressions and return a scalar
Expr from its spectrum viaadc::real_eig_minmax(max imaginary part as a complex-eigenvalue
witness, or the real-part bounds). The codegen emits a named device-clean functor (no extended
lambda), som.projectioncan express a branchless "if a moment matrix has a complex eigenvalue,
correct it" rule (unblocks the native relaxation15 projector, ADC-275). Additive: the existing
expression set andm.projection(ADC-177) are unchanged. -
Documentation rebuilt around a Diataxis navigation (ADC-248): Getting started, Tutorials,
Concepts (11 pages, ADC-249), How-to (12 task pages), Simulation, AMR, Running, Advanced topics,
Reference and Development sections, plus a Quickstart page and an internal documentation style
guide (ADC-250). Pages are kebab-case. -
Embedded C++ reference in the Sphinx site via doxysphinx (ADC-149), with a modern Doxygen
theme and full dot diagrams (ADC-239). -
Documentation-as-code tooling: per-page
docmap.tomlwith owner and freshness plus an
example harness (ADC-147), a doc taxonomy and a stack ADR (ADC-146), and CI doc lanes (a light PR
lane and a weekly heavy lane with lld and ccache, ADC-151/225). -
Quality tooling / static analysis (ADC-105): dedicated CI workflow
.github/workflows/quality.yml,
off the PR critical path (weekly Sunday cron +workflow_dispatch+qualitylabel). Five
informative (non-blocking) jobs:clang-format(.clang-format), strict warnings
(ADC_ENABLE_WARNINGS),clang-tidy(.clang-tidy), ASan+UBSan sanitizers (ADC_ENABLE_SANITIZERS,
ci-warnings/ci-asanpresets) and CodeQL. CMake options OFF by default (emptyadc_dev_options
target), soci.yml, local builds andadc_casesare unchanged. Seedocs/QUALITY_TOOLING.md. -
Fuzzing, coverage and developer automation (ADC-113): invariant-checked libFuzzer harnesses in
fuzz/(Box2D, Berger-Rigoutsos clustering,real_eig_minmax; optionADC_BUILD_FUZZING+
ci-fuzzpreset, clang), gcov/gcovr coverage (ADC_ENABLE_COVERAGE+ci-coveragepreset),
Python ruff lint ([tool.ruff]), opt-in pre-commit hooks (.pre-commit-config.yaml: clang-format
and ruff at commit), and two morequality.ymljobs (fuzz,coverage) on the same weekly
informative cadence; the default build stays bit-unchanged. -
Repository health and GitHub hygiene: BSD-3
LICENSEand license declaration,CONTRIBUTING,
SECURITY,.gitattributes, PR and issue templates (ADC-223/224/244/246), a root-hygiene guard
(ADC-169), Dependabot weekly Actions bumps (ADC-117), a release workflow that turns av*tag
into a GitHub Release from this changelog (ADC-234), anddocs/VERSIONING.mdwith the bump rules
(ADC-232/237). -
Shared C++ test harness (
test_harness.hpp,bench/common.hpp, ADC-215); a Schur-split test
with an AMR guard onadd_blockand auto-skip without Kokkos (ADC-207). -
CI:
ci.ymlsplit into parallelgate-cpp/gate-pythonlanes withmoldand path
routing (ADC-171). -
Moment-model documentation: a step-by-step HyQMOM tutorial, a moments-and-closures concept
page, a moment-models reference, andadc.moments(build_moment_model,gaussian_closure,
lorentz_sources) added to the Python API reference (autodoc). -
Generic pointwise post-step PROJECTION hook (ADC-177):
m.projection([...])on the DSL side
(C++ traitHasPointwiseProjection, compiled like the flux/source), applied bySystemat the
end of every whole macro-step (never per RK stage) on the valid cells of each block -- replaces
the per-cell Python callback (aotandproductionbackends;prototypeand
target="amr_system"reject it explicitly). Addsdsl.sign(x)(branch-free mask selections,
differentiable). Seedocs/DSL_API.mdsection 5.
Changed
- Kokkos is the only on-node backend (ADC-263): the standalone OpenMP path is removed (the
ADC_USE_OPENMPoption,find_package(OpenMP), the mutual-exclusion check and every#pragma omp
or manual host loop);ADC_USE_KOKKOSdefaults ON and is fatal if disabled. Serial runs through
Kokkos Serial, threads through Kokkos OpenMP, GPU through Kokkos Cuda/HIP, all chosen at Kokkos
install time (Kokkos_ENABLE_*). Thefor_each_cellseam#errors withoutADC_HAS_KOKKOS; the
standard is pinned to C++20. The DSL loaders (compile_aot/compile_native) build against Kokkos
and the.socache is keyed on Kokkos state. - AOT DSL backend compiles at native optimization flags (ADC-201):
compile_aot(and the hybrid
AOT path) dropped the hardcoded-O2(about 1.48x slower) for the native_dsl_optflags()
(default-O3 -DNDEBUG, overridable via$ADC_DSL_OPTFLAGS); only the prototype JIT stays at
-O2. Anaot-optflagsmarker in the.socache key prevents serving a stale-O2binary. - Hybrid AOT models build with the Kokkos toolchain (ADC-103): since the Kokkos-only switch,
HybridModel.compile(backend="aot")uses the native Kokkos compiler and flags (with macOS
-undefined dynamic_lookup) and raises a clearADC_KOKKOS_ROOTerror when no Kokkos is visible;
the prototype JIT stays pure-host. - Leaner DSL codegen (ADC-200):
emit_cpp_*now emit only the primitives transitively live in
each method (no dead closure or itssqrt), values bit-identical; an opt-inhoist_reciprocals=True
hoists1/xonce for a recurring conservative denominator and turns those divisions into products
(off by default, since it changes rounding). - Mixed relative/absolute stop criterion for GeometricMG (ADC-202):
System.set_poisson(..., abs_tol=0.0)adds an absolute residual floor, so the stop test becomes
residual <= max(rel_tol*r0, abs_tol)with an early exit whenr0is already under the floor
(avoids over-solving an already-converged off-stepsolve_fields).abs_tol=0keeps the historical
relative behavior bit-identical; inert for the FFT solver. - Higher default QR cap in
dense_eig(ADC-195): the default iteration cap ofreal_eig_minmax
rises from 30 to 100 so near-degenerate companion blocks (HyQMOM 5x5, about 42 iterations) converge
instead of falling back to Gershgorin (which over-estimated the wave speed about 9x); a new optional
fallbackout-parameter reports when the fallback fires. - Overflow-safe index arithmetic in PoissonFFT (ADC-286): the hot indexing (row offsets,
eigenvalue scaling, transpose buffers) widens tosize_tbefore multiplying, removing an int*int
overflow past INT_MAX on large multi-rank grids (CodeQL). Numerically neutral, bit-identical under
INT_MAX. - Documentation translated to English: the whole Sphinx site (ADC-228), the root design guides
and this changelog (ADC-241), the remaining French docs (ADC-245),CONTRIBUTING/SECURITY/
DOC_QUALITY(ADC-227), and a restructured English README with a translation glossary
(ADC-119/236/218). - BREAKING (C++): facade parameters regrouped into a POD struct, source-incompatible for C++
callers; the Python API is unchanged (ADC-214). - Docs version single-sourced (ADC-233): the docs build derives the version from
project(VERSION)inCMakeLists.txt(scripts/build_docs.shinjects the Doxygen
PROJECT_NUMBER,docs/sphinx/conf.pyreads it), so Doxygen and Sphinx no longer drift. - Portability (LLP64 / Windows data model):
longtoint64_tinmesh/and thebox_hash
key, removing undefined<< 32shifts (ADC-209/216). - Internal C++ cleanups: rule of five on owning types (ADC-212), bit-exact factorizations of
duplicated FV/MG and Newton-Jacobian code (ADC-213), residual extended device lambdas converted
to named functors (ADC-210), hardened runtime guards (ADC-211), and a coding-standards and
comments audit (ADC-124/125). - Code comments and Python docstrings translated to English (ADC-272): all of
include/adc/**,
python/adc/**(including the pybind bindings) and theCODE_DOCUMENTATION_CONVENTIONguide; the
published/cpp/Doxygen reference and the Python autodoc now render in English. Code structure is
byte-identical; codegen-template strings and cross-TU dispatch tokens are kept verbatim.
Fixed
- Periodic theta ghosts in the polar Schur source coupling: the polar condensed-Schur stepper
and the polar Krylov solver now force the azimuthal (theta) ghosts of phi periodic instead of
honoring the caller's four-face Dirichlet BCRec. The theta=0/2pi seam was filled by odd reflection
(ghost = -phi), injecting a dipole radial-momentum kick that grew like O(1/h) and diverged the
polar Hoffart run near t~0.01. A step with the System-style Dirichlet BCRec is now bit-identical to
the canonical theta-periodic step. - Stale phi ghosts on the direct FFT Poisson path (ADC-175):
PoissonFFTSolver::solve()now does
a periodicfill_boundaryon the phi ghosts after the solve; the direct solver wrote only valid
cells, so a centered grad-phi for an electric source read stale domain-edge ghosts (wrong Ex on the
boundary ring withsolver="fft"). - Ghost-width guard on the EB and polar FV operators (ADC-221): the structural
require_reconstruction_ghosts<Limiter>check (ADC-163) now also runs at the entry of
assemble_rhs_ebandassemble_rhs_polar, which reused the same reconstruction stencil with no
input validation (boundLimiter::n_ghost, host-only; no sane production caller triggers it). - Non-circular spectral check in
check_model:check_modelnow boundsmax_wave_speedby the
spectral radius of the full dense flux Jacobian (central differences, independent of anyblocks=
partition), catching aset_wave_speeds_from_jacobianpartition that silently fails to bound the
spectrum (under-estimated CFL); tunable viajac_rtol/jac_atol. Also corrects a misleading
duplicate-index message. - clang portability:
make_system_couplerfactory replaces CTAD on theSystemCoupleralias
template, which GCC accepts but clang rejects (P1814) -- this broke every clang build of the
coupling tests, surfaced by the new TSan job (ADC-302). - Heap-buffer-overflow masked on disc geometry, caught by a ghost-width guard at FV operator entry
(ADC-163). - Comment rot: 10 inaccurate comments corrected (ADC-208); broken sister-solver links in the docs
index. - Docs (Pages) build:
suppress_warnings = ["docutils"]set unconditionally in
docs/sphinx/conf.pysosphinx -Wno longer fails on autodoc-rendered Doxygen@param
docstrings (the meaningful broken-reference and toctree checks stay strict). mastergate unblocked (ADC-281):test_dispatch_tagsgreps the dispatch-registry error
fragments, which ADC-272 (#105) had translated to English indispatch_tags.hppwithout updating
the test -- reconciled the grepped fragments (unknown limiter/unknown Riemann flux/
unsupported/polar).- Python test message-assertions reconciled with ADC-272 translation (ADC-283): ~26 assertions
across 21python/tests/files grepped now-translated French error fragments (masked by the
gate-python swallow, ADC-112). Reconciled to assert language-stable substrings (echoed values,
quoted tokens) so they survive the ongoing translation; also reconciled the order-sensitive
ABI incompatiblegreps with the source'sincompatible ABI-- thetest_dsl_production{,_amr}.py
asserts and the C++test_amr_native_loader.cppguard (test_native_abi_std.pyrides along under
this umbrella) -- plus the stale forward-order wording in comments and hints (bindings.cpp,
__init__.py,dsl.py,python/CMakeLists.txt). - MPI FFT rejection test (ADC-282):
test_mpi_system_fftgreps the translated
fft solver unsupported under MPImessage, completing the post-ADC-272 test fixups alongside
ADC-281/283. - CI hardening: the weekly quality jobs are bounded against cold-cache OOM (serial instrumented
ci-asan/ci-coveragebuilds,timeout-minutescaps, and a single Ninja pool for the heavy
Kokkos translation units; ADC-284/290), CodeQL is scoped to the adc sources to drop 187
vendored-Kokkos findings (ADC-285), seven orphan DSL tests are registered in ctest with a
self-containedADC_KOKKOS_ROOT(ADC-104), and ano-ai-authorsguard rejects AI authorship or
co-author trailers.