adc_cppΒΆ

adc_cpp: adc_cpp
adc_cpp 0.3.0
Model-free C++23 core for coupled hyperbolic-elliptic systems on adaptive (AMR) meshes, with MPI and GPU (Kokkos) backends
adc_cpp

PoPS - Plasma-Oriented PDE Solver

A model-free C++23 core for coupled hyperbolic-elliptic systems on adaptive (AMR) meshes.
C++23 CMake Backends Python License

PoPS - Plasma-Oriented PDE Solver


PoPS is a model-free engine with a library of generic physics bricks (include/pops/physics/) and Python bindings (pops). It names no scenario; it provides generic bricks composed into a CompositeModel. Named scenarios (diocotron, Euler-Poisson, two-fluid) live in adc_cases.

On a Cartesian adaptive mesh, the core advances a hyperbolic part U coupled to an elliptic part phi:

d U / d t + div F(U, aux) = S(U, aux)
D phi = f(U)

The coupling flows through the aux channel at each step. The base contract is (phi, grad_x, grad_y); a model may declare n_aux to read extra fields (B_z, T_e).

Table of contents

  • Prerequisites
  • Installation
  • Usage
  • Documentation
  • Versioning
  • Contributing
  • License

Prerequisites

  • C++20 compiler: AppleClang 16+, GCC 13+, Clang 17+ (nvcc_wrapper for the CUDA target).
  • CMake >= 3.21: the build is driven by presets (CMakePresets.json).
  • Kokkos 4.2+: the only on-node backend, required. No need to pre-install it; if it is not found, CMake fetches and builds it (FetchContent).
  • MPI *(optional, -DPOPS_USE_MPI=ON: halos and distributed FFT)*.
  • HDF5 parallel *(optional, -DPOPS_USE_HDF5=ON: DataWriter)*.
  • Python 3.12 + numpy *(optional, the pops bindings; conda env via scripts/setup_env.sh)*.

Per-platform backend coverage and known pitfalls (macOS, CUDA, conda, CI runners): docs/BACKEND_COVERAGE.md.

Installation

Three ways. Build-from-source details live in the installation guide rather than inline here.

C++ core, via CMake presets:

git clone https://github.com/wolf75222/adc_cpp.git && cd adc_cpp
cmake --preset serial && cmake --build --preset serial && ctest --preset serial

The Ninja build already uses every core; pin it to fewer jobs on a constrained machine with cmake --build --preset serial -j<N>. The serial test preset runs tests one at a time; parallelize with ctest --preset serial -j<N> (-j$(nproc) on Linux, -j$(sysctl -n hw.ncpu) on macOS), and add --output-on-failure for logs. Two other presets build a parallel backend instead of the serial one (both read $CONDA_PREFIX, so the conda env must be active):

cmake --preset parallel && cmake --build --preset parallel && ctest --preset parallel # threaded, Kokkos OpenMP
cmake --preset mpi && cmake --build --preset mpi && ctest --preset mpi # distributed, MPI

Each preset writes into its own folder (build, build-kokkos, build-mpi). Backends and runtime thread control (pops.set_threads()) are covered in the installation guide.

Python module (pops): scripts/setup_env.sh creates the conda env and pins the platform toolchain, then scripts/build_python.sh builds and installs the module in one command (it sizes the heavy-TU pool, exports the discovery vars, and ends on pops.doctor()); pip install . (scikit-build-core) drives the build directly if you prefer. Backends are selected by environment variables (POPS_USE_MPI, Kokkos_ROOT, ...). scripts/uninstall_pops.sh reverses the two setup scripts when you want a clean teardown.

bash scripts/setup_env.sh # conda env + toolchain
bash scripts/build_python.sh # build + install, then pops.doctor()
bash scripts/uninstall_pops.sh # full teardown (env + caches); --keep-env drops only the module
# or, by hand: pip install . # see the installation guide for backends

Released versions and binaries: the Releases page.

Usage

Diocotron instability, 3-level AMR, on ROMEO

Validation scenario: diocotron instability (E x B drift) on a 3-level nested AMR hierarchy, ROMEO (96 cores). Reproducible local version (Python facade): adc_cases/diocotron_amr.

From a C++ project

The core is header-only and consumed via find_package(pops) or FetchContent:

include(FetchContent)
FetchContent_Declare(adc_cpp GIT_REPOSITORY https://github.com/wolf75222/adc_cpp.git)
FetchContent_MakeAvailable(adc_cpp) # adc_cpp's own tests are not built for the consumer
target_link_libraries(my_app PRIVATE pops::pops)

Define a type that satisfies the PhysicalModel concept, wrap it in a Coupler<Model, Elliptic> (or AmrCouplerMP for AMR), and advance in time.

From Python

The public path is typed and compiled. Python builds an inert pops.Case; C++/Kokkos/MPI executes the run. User choices are descriptors, not string selectors. The reduced diocotron example below couples a scalar density to a Poisson field:

import numpy as np
import pops
from pops.time import Program
from pops.lib.time import ssprk3
from pops.physics import Model
from pops.math import laplacian, grad, div, ddt
from pops.mesh.cartesian import CartesianMesh
from pops.mesh.layouts import Uniform
from pops.fields import PoissonProblem
from pops.fields.bcs import Periodic
from pops.fields.rhs import ChargeDensity
from pops.solvers.elliptic import GeometricMG
from pops.numerics.riemann import Rusanov
from pops.numerics.reconstruction.limiters import Minmod
from pops.codegen import Production
m = Model("diocotron")
U = m.state("U", components=["ne"], roles={"ne": "density"})
(ne,) = U
phi = m.field("phi")
m.solve_field("fields_from_state",
equation=(-laplacian(phi) == ne),
outputs={"phi": phi, "grad_x": grad(phi).x, "grad_y": grad(phi).y},
solver=GeometricMG())
E = m.vector_field("E", x=-grad(phi).x, y=-grad(phi).y)
flux = m.flux("F", on=U, x=[ne * E.y], y=[ne * (-E.x)], waves={"x": [E.y], "y": [-E.x]})
m.rate("explicit_rate", ddt(U) == -div(flux))
m.check()
poisson = PoissonProblem(name="phi", unknown="phi",
equation=(-laplacian("phi") == ChargeDensity.from_blocks("ne")),
bcs=(Periodic(),), solver=GeometricMG())
time = Program("advance")
ssprk3(time, "ne")
case = (pops.Case(layout=Uniform(CartesianMesh(n=96, L=1.0, periodic=True)), name="diocotron")
.block("ne", physics=m, spatial=pops.FiniteVolume(limiter=Minmod(), riemann=Rusanov()))
.field(poisson)
.time(time))
compiled = pops.compile(case, backend=Production())
sim = pops.bind(compiled, state={"ne": ne0}) # ne0: initial density (2D array)
sim.run(0.1, cfl=0.4)
sim.write("ne.npz", format="npz") # save the block states (npz; "vtk" also available)

For an adaptive run, swap the layout to pops.mesh.layouts.AMR(mesh, max_levels=2, ratio=2) and author the refinement with typed pops.mesh.amr policies. pops.bind builds the AMR runtime from that layout. Users do not pass a public target string and do not instantiate the AMR runtime as the front door. Step-by-step tutorial: getting-started/tutorial. Reference: native-bricks, symbolic-dsl, public API contract.

Documentation

Core layers

Layer Role Entry point
core/ types, state, PhysicalModel, EquationBlock, CoupledSystem physical_model.hpp
physics/ generic bricks composed into a CompositeModel composite.hpp
numerics/ reconstruction (Minmod / VanLeer / WENO5), flux (Rusanov / HLL / HLLC / Roe) reconstruction.hpp
numerics/elliptic/ EllipticSolver concept, geometric multigrid, FFT, composite FAC elliptic_solver.hpp
numerics/time/ SSP-RK, multirate scheduler, IMEX, splitting, AMR engine numerics/time/
coupling/ Coupler, SystemCoupler, AmrSystemCoupler, AmrCouplerMP coupler.hpp
amr/, mesh/, parallel/ Berger-Rigoutsos clustering, regrid, MultiFab, MPI comm seam amr/
runtime/ System / AmrSystem facades, model_factory, DSL, aux channel system.hpp

Ecosystem

Repo Role
adc_cpp (this repo) hyperbolic-elliptic core on AMR, with GPU / MPI / Kokkos
adc_cases applications: named models, facades, examples, Python
poisson_cpp Poisson solvers (Thomas, SOR, CG, DST, multigrid)
advection_cpp advection, Burgers, Chorin Navier-Stokes
euler_cpp 2D Euler, viscous Navier-Stokes, plasma sources

Versioning

PoPS follows Semantic Versioning. The public API under guarantee and the bump rules are declared in docs/VERSIONING.md. Available versions and their change logs: the Releases page and CHANGELOG.md. The project is in 0.y.z initial development: the public API may still change until 1.0.0.

Contributing

Build, test and workflow conventions: CONTRIBUTING.md.

License

BSD-3-Clause. See [LICENSE](LICENSE).