From 67366133521a8d3bebbada4473105f120a5ce819 Mon Sep 17 00:00:00 2001 From: mayani_s Date: Fri, 26 Jun 2026 14:24:52 +0200 Subject: [PATCH] change alpine --- .../examples/alpine-manager-hierarchy.qmd | 235 ++++++++++++------ 1 file changed, 164 insertions(+), 71 deletions(-) diff --git a/sections/examples/alpine-manager-hierarchy.qmd b/sections/examples/alpine-manager-hierarchy.qmd index 9fd7804..f83bb21 100644 --- a/sections/examples/alpine-manager-hierarchy.qmd +++ b/sections/examples/alpine-manager-hierarchy.qmd @@ -1,18 +1,116 @@ # ALPINE Manager Hierarchy {#sec-alpine-manager-hierarchy} -Source focus: `alpine/LandauDamping.cpp`, `alpine/LandauDampingManager.h`, `alpine/AlpineManager.h`, `src/Manager/BaseManager.h`, and `src/Manager/PicManager.h`. +ALPINE is IPPL's application layer: a collection of plasma-physics **mini-apps** in the `alpine/` directory that run full particle-in-cell (PIC) simulations end to end. They are not isolated library demos. Each mini-app wires together particles, fields, interpolation, Poisson solvers, MPI load balancing, and diagnostics the way a real simulation code would. -The `alpine` directory contains production-style miniapps that use IPPL as an application framework rather than as isolated library calls. The Landau damping miniapp is the most compact example of this style: the executable parses command-line parameters, constructs a manager, calls `pre_run()`, and delegates the simulation loop to the generic manager interface. Read this page together with @sec-theory for the Vlasov--Poisson/PIC model and @sec-particle-mesh for interpolation and load-balancing concepts. +This chapter explains what those mini-apps are for, how they are organized, and how the **manager hierarchy** keeps application logic separate from reusable PIC infrastructure. We use **Landau damping** as the main walkthrough because it is the smallest complete example; the same pattern applies to the other ALPINE applications. -## Design intent +For the underlying PIC model, see @sec-theory. For gather/scatter and load balancing, see @sec-particle-mesh. For solver options, see @sec-poisson-solvers and the runnable `LandauDamping` example in @sec-examples. -The manager hierarchy separates three concerns: +## What ALPINE mini-apps are -1. **Simulation lifecycle**: when setup, time stepping, and post-step diagnostics occur. -2. **PIC data ownership**: where particle, field, solver, and load-balancer objects live. -3. **Problem physics**: how Landau damping initializes particles and advances the Vlasov--Poisson system. +IPPL ships two kinds of executables that look similar from the outside but serve different goals: -This separation is useful for library users because the Landau miniapp shows which pieces must be supplied for a new PIC application. It is useful for library developers because the same interfaces expose where to add new solvers, interpolation methods, diagnostics, or load-balancing policies. +| | Unit tests and examples (`test/`, `examples/`) | ALPINE mini-apps (`alpine/`) | +|---|---|---| +| **Goal** | Verify one subsystem (a solver, FFT layout, CIC gather/scatter, …) | Run a complete PIC-style plasma simulation | +| **Scope** | Often a single loop or manufactured solution | Domain setup, particles, time stepping, field solve, diagnostics, scaling | +| **Typical user** | Developer validating a change | Application author learning how to assemble IPPL, or researcher running a benchmark | +| **Code style** | Direct calls into IPPL classes | Thin `main()` + a **manager** class that owns the simulation | + +Mini-apps therefore serve three practical purposes: + +1. **Reference applications** — they show how to combine IPPL building blocks into a working PIC code without reimplementing the standard loop. +2. **Correctness and performance benchmarks** — standard plasma problems with known behavior are used to test solvers, preconditioners, and Kokkos/MPI portability on large machines [@muralikrishnan2024scalingPicMiniapps]. +3. **Templates for new codes** — to add a new simulation, you typically subclass the existing managers and override physics-specific methods rather than writing a PIC driver from scratch. + +At a high level, every ALPINE mini-app follows the same skeleton: + +```{mermaid} +flowchart TB + main["main() parses CLI"] + pre["manager.pre_run()"] + loop["manager.run(nt)"] + step["advance(): push → scatter → solve → gather → push"] + main --> pre + pre --> loop + loop --> step + step --> loop +``` + +The executable stays small; the manager owns containers, solvers, and the time-stepping policy. + +## Applications in `alpine/` + +CMake builds three manager-based executables from `alpine/CMakeLists.txt`. Each has a thin driver (`*.cpp`) and a problem-specific manager that subclasses `AlpineManager`: + +| Executable | Manager class | Physical problem | +|---|---|---| +| `LandauDamping` | `LandauDampingManager` | Electrostatic Landau damping on a periodic domain | +| `PenningTrap` | `PenningTrapManager` | Magnetized plasma in a Penning-trap geometry with imposed $\mathbf{E}$ and $\mathbf{B}$ fields | +| `BumponTailInstability` | `BumponTailInstabilityManager` | Bump-on-tail (or related beam–plasma) velocity instability on a periodic domain | + +All three share the same command-line shape: + +```text +srun ./ Nx Ny Nz Np Nt [preconditioner args...] --overallocate --info +``` + +Landau damping is documented in detail below because it is the smallest complete walkthrough. The other managers override the same hooks—`pre_run()`, `initializeParticles()`, `advance()`, and `dump()`—while reusing `AlpineManager` for deposition, gather, solver dispatch, and load balancing. + +### Landau damping in brief + +Landau damping is a classic kinetic-plasma test case: a small sinusoidal perturbation in particle density launches an electrostatic wave that decays in time because of resonant particle–wave interaction (no collisions required). `LandauDampingManager` sets a periodic box with $k_w=0.5$, perturbation amplitude $\alpha=0.05$, Maxwellian velocities, and positions sampled from $1+\alpha\cos(k_w x)$. + +```bash +srun ./LandauDamping 64 64 64 1048576 20 FFT 0.1 LeapFrog --info 5 +``` + +This constructs the manager, calls `pre_run()` to build fields and particles, then runs 20 Leapfrog steps with an FFT Poisson solve. ORB load balancing triggers when the particle imbalance exceeds `lbthres` (here 10%). + +### Penning trap in brief + +`PenningTrapManager` models particles in a static trap: an external quadrupole-like electric potential plus a uniform axial magnetic field $B_z = 5$ (in code units). Self-fields from the deposited charge are added to these external fields during the push. The domain is periodic on $[0,20]^3$ with Gaussian spatial and velocity distributions centered in the box. The time integrator is a magnetized Leapfrog variant (Boris-style $\mathbf{v}\times\mathbf{B}$ coupling in the velocity kicks), not the purely electrostatic push used in Landau damping. + +```bash +srun ./PenningTrap 128 128 128 10000 300 FFT 0.01 LeapFrog --overallocate 1.0 --info 10 +``` + +Because the trap study often needs many time steps, this mini-app is a common target for iterative and preconditioned Poisson solvers (`CG`, `PCG`, and the truncated-Green `TG` path). + +### Bump-on-tail instability in brief + +`BumponTailInstabilityManager` initializes a periodic electrostatic setup with a bulk Maxwellian plus a fast beam in velocity space—the classic bump-on-tail configuration that drives a kinetic instability. A sinusoidal density perturbation is applied along the last spatial dimension. The standard electrostatic Leapfrog cycle applies (no external $\mathbf{B}$ field). Optional phase-space dumps exist behind a compile-time flag (`EnablePhaseDump`). + +```bash +srun ./BumponTailInstability 128 128 128 10000 10 FFT 0.01 LeapFrog --overallocate 2.0 --info 10 +``` + +## Why a manager hierarchy? + +A PIC simulation repeats the same structural steps every time step (see @sec-theory and @sec-particle-mesh): push particles, deposit charge, solve for the field, gather forces, push again, migrate particles across MPI ranks, and optionally repartition. ALPINE factors this into layers so that **only the physics-specific pieces change** between mini-apps: + +| Layer | Responsibility | Changes when you add a new mini-app? | +|---|---|---| +| `BaseManager` | Simulation lifecycle: `pre_run()`, `run(nt)` | +| `PicManager` | Owns particle and field containers, solver, load balancer; requires `par2grid()` / `grid2par()` definitions of PIC scatter/gather | +| `AlpineManager` | Contains all common ALPINE functions, such as Cloud-in-Cell scatter/gather, charge conservation checks, and default diagnostics | +| `LandauDampingManager` (or others) | Domain, initial conditions, time integrator, problem-specific output - This is where the physics is | + +Concrete manager subclasses: `LandauDampingManager`, `PenningTrapManager`, and `BumponTailInstabilityManager`, all derived from `AlpineManager`. + +Source files for this stack: + +| File | Role | +|---|---| +| `alpine/LandauDamping.cpp` | Landau damping driver | +| `alpine/LandauDampingManager.h` | Landau-specific physics | +| `alpine/PenningTrap.cpp` | Penning trap driver | +| `alpine/PenningTrapManager.h` | Trap fields, magnetized push, diagnostics | +| `alpine/BumponTailInstability.cpp` | Bump-on-tail driver | +| `alpine/BumponTailInstabilityManager.h` | Beam–plasma ICs and instability diagnostics | +| `alpine/AlpineManager.h` | Shared Particle-in-Cell functions for ALPINE, inherits from PicManager which inherits from BaseManager | +| `alpine/FieldSolver.hpp` | Solver name → concrete Poisson backend | +| `alpine/FieldContainer.hpp`, `alpine/ParticleContainer.hpp`, `alpine/LoadBalancer.hpp` | Containers for fields and particles used by ALPINE, as well as the load balancing scheme | ## Class hierarchy @@ -56,12 +154,35 @@ classDiagram +dump() } + class PenningTrapManager~T, Dim~ { + +pre_run() + +initializeParticles() + +advance() + +LeapFrogStep() + +dump() + } + + class BumponTailInstabilityManager~T, Dim~ { + +pre_run() + +initializeParticles() + +advance() + +LeapFrogStep() + +dump() + } + BaseManager <|-- PicManager PicManager <|-- AlpineManager AlpineManager <|-- LandauDampingManager + AlpineManager <|-- PenningTrapManager + AlpineManager <|-- BumponTailInstabilityManager ``` -`BaseManager` defines the lifecycle contract. Its `run(nt)` method calls `pre_step()`, `advance()`, and `post_step()` for each time step. `PicManager` specializes this contract for particle-in-cell applications by requiring `par2grid()` and `grid2par()` and by owning the containers and services that a PIC loop needs. `AlpineManager` provides the common ALPINE implementation of particle-field transfers, charge conservation checks, density normalization, and default post-step time/diagnostic handling. `LandauDampingManager` supplies the application-specific setup, particle sampling, Leapfrog integrator, and Landau diagnostics. This makes the manager stack a concrete bridge between the high-level PIC loop in @sec-particle-mesh and the performance-portable execution model in @sec-performance-portability. +- **`BaseManager`** defines when setup, time stepping, and post-step work run. `run(nt)` calls `pre_step()`, `advance()`, and `post_step()` each step. +- **`PicManager`** specializes that contract for PIC: it holds the particle container, field container, field solver, and load balancer, and requires particle-to-grid and grid-to-particle transfers. +- **`AlpineManager`** implements those transfers for ALPINE (CIC for spectral/FD solvers, FEM assembly for finite-element solvers), normalizes deposited charge, and provides default timing and dump hooks. +- **Problem managers** (`LandauDampingManager`, `PenningTrapManager`, `BumponTailInstabilityManager`, …) fill in domain setup, particle sampling, the time integrator, and diagnostics. Penning trap additionally applies external $\mathbf{E}$ and $\mathbf{B}$ during the push; the other two are electrostatic Leapfrog. + +Together, this stack connects the abstract PIC loop in @sec-particle-mesh to the performance-portable execution model in @sec-performance-portability. ## Object ownership @@ -107,16 +228,15 @@ classDiagram LoadBalancer --> FieldSolver ``` -The manager owns shared pointers to these components through `PicManager`. During `pre_run()`, `LandauDampingManager` creates them in dependency order: +`PicManager` stores shared pointers to these objects. `LandauDampingManager::pre_run()` constructs them in dependency order: -| Step | Object or operation | Role in the miniapp | +| Step | Object or operation | Role | |---|---|---| -| 1 | Domain, spacing, time step, total charge | Defines the periodic Landau damping problem and numerical resolution. | -| 2 | `FieldContainer` | Allocates the mesh, `FieldLayout`, electric field `E`, charge density `rho`, and potential `phi` when required by the selected solver. | -| 3 | `ParticleContainer` | Builds the particle spatial layout from the field mesh/layout and registers charge `q`, velocity `P`, and gathered electric field `E`. | -| 4 | `FieldSolver` | Selects FFT, CG, PCG, FEM, or preconditioned FEM solve paths behind the `FieldSolverBase` interface; the generic ALPINE solver also has open-boundary variants, but Landau damping rejects `OPEN` because the problem is periodic. | -| 5 | `LoadBalancer` | Couples ORB repartitioning to the current fields, particles, and solver. | -| 6 | `initializeParticles()` | Samples perturbed Landau positions and Maxwellian velocities, assigns charge, and optionally performs the initial FEM migration. | +| 1 | Domain, spacing, time step, total charge | Defines the periodic Landau problem and grid resolution | +| 2 | `FieldContainer` | Mesh, `FieldLayout`, electric field `E`, charge density `rho`, and potential `phi` when the solver needs it | +| 3 | `ParticleContainer` | Particle layout aligned with the field mesh; registers position `R`, velocity `P`, charge `q`, and gathered field `E` | +| 4 | `FieldSolver` | Dispatches to FFT, CG, PCG, FEM, or preconditioned FEM via `FieldSolverBase` (see accepted types for each application) | +| 5 | `LoadBalancer` | ORB repartitioning of domain - tied to layout of fields and particles | ## Runtime lifecycle @@ -153,67 +273,40 @@ sequenceDiagram end ``` -The important design point is that `main()` does not know the details of particle migration, charge scatter, field solution, or diagnostics. Those details are encoded in the manager hierarchy, so a new miniapp can reuse the lifecycle while replacing only the physics-specific manager methods. - -## Particle--field transfer policy +`main()` never calls scatter, gather, or migration directly. This lets new mini-apps swap physics inside `advance()` while reusing the same outer loop. -`AlpineManager` is the point where the solver choice changes the interpolation path. The path is not only a software switch: it also determines whether the field quantities are cell-centered mesh fields or finite-element quantities reconstructed through the solver's space. +## Landau-specific physics and time stepping -| Manager method | FFT/CG/PCG path | FEM/FEM_PRECON path | -|---|---|---| -| `par2grid()` | `scatterCIC()` scatters particle charge to cell-centered `rho`. | `scatterFEM()` assembles the finite-element right-hand side from particles. | -| `grid2par()` | `gatherCIC()` gathers grid electric field `E` to particle positions. | `gatherFEM()` interpolates the gradient of `phi` to particles using the solver's finite-element space. | -| Density normalization | Divides by cell volume and subtracts the uniform ion background for non-open solvers. | Uses the assembled finite-element quantity and the same periodic background convention. | +`LandauDampingManager` encodes the benchmark setup: -This is the local extension point for interpolation and deposition. A new solver can remain behind `FieldSolverBase`, but if it changes the mathematical meaning, centering, or finite-element space of the field quantities, the manager transfer methods must make that explicit. +- Periodic domain with \(r_\min=0\), \(r_\max=2\pi/k_w\), perturbation amplitude \(\alpha=0.05\), and \(k_w=0.5\). +- Positions sampled from \(1+\alpha\cos(k_w x)\) via inverse transform; velocities from a normal (Maxwellian) distribution. +- Total charge split uniformly across macro-particles. +- Time step \(\Delta t = \min(0.05,\, 0.5 \min(\Delta x_d))\) from the grid spacing. +- Only the `LeapFrog` integrator is accepted in this mini-app. -## Solver and command-line notes +Each Leapfrog step is the standard electrostatic PIC cycle: -The Landau executable is currently fixed to `Dim = 3` and `T = double`. Its solver argument is passed through to `FieldSolver`, but `LandauDampingManager::pre_run()` explicitly rejects `OPEN` because open boundaries are incompatible with this periodic benchmark. The practical Landau choices are: +1. Half-step velocity kick from gathered \(\mathbf{E}\). +2. Full-step position push. +3. Particle migration (`ParticleBase::update()`). +4. ORB repartition if load imbalance exceeds the threshold. +5. Charge deposition (`par2grid()`). +6. Field solve (`runSolver()`). +7. Field gather (`grid2par()`). +8. Second half-step velocity kick. -| Solver argument | Meaning in this miniapp | -|---|---| -| `FFT` | Periodic FFT Poisson solve, returning the electric-field gradient directly. | -| `CG` | Matrix-free conjugate-gradient Poisson solve with periodic potential boundary conditions. | -| `PCG` | Preconditioned CG path; the executable currently reads a fixed five-token preconditioner block. | -| `FEM` | Finite-element Poisson solve; `rho` and `phi` are periodic fields and transfers use FEM assembly/interpolation. | -| `FEM_PRECON` | Preconditioned finite-element path with the same fixed preconditioner argument convention as `PCG`. | +Diagnostics (`dump()`, `dumpLandau()`) report field and particle quantities used to verify damping behavior. -The current parser consumes five strings after `PCG` or `FEM_PRECON`, even though some preconditioners use fewer parameters. For example, `ssor inner outer omega` uses three values after the preconditioner name, so a padding token is still needed before IPPL options such as `--overallocate`. +## Building a new ALPINE-style mini-app -## LandauDamping-specific behavior +Use Landau damping as the template. Override only what your physics requires: -`LandauDampingManager` provides the physics specialization: - -- The domain is periodic with \(r_\min=0\), \(r_\max=2\pi/k_w\), perturbation amplitude \(\alpha=0.05\), and \(k_w=0.5\). -- Particle positions are sampled from \(1+\alpha\cos(k_w x)\) through inverse-transform sampling. -- Particle velocities are sampled from a normal distribution. -- The total particle charge is distributed uniformly over macro-particles. -- The time step is chosen from the grid spacing as `min(0.05, 0.5 * min(hr))`. -- The only accepted time stepper in this miniapp is `LeapFrog`. - -The Leapfrog step is the standard PIC cycle: - -1. Kick particle velocities by a half step using the gathered electric field. -2. Drift particle positions. -3. Migrate particles to the owning ranks through `ParticleBase::update()`. -4. Repartition the field layout and particle layout with ORB if the load-balancer threshold is exceeded. -5. Scatter charge to the grid. -6. Solve the field equation. -7. Gather electric field back to particles. -8. Kick particle velocities by the second half step. - -## How to read or extend this miniapp - -For a new ALPINE-style PIC miniapp, use Landau damping as the template: - -| If you need to change... | Start in... | Typical change | +| If you need to change… | Start in… | Typical change | |---|---|---| -| The problem setup | `LandauDampingManager::pre_run()` | Domain, boundary assumptions, solver parameters, initial fields. | -| Initial particle distribution | `initializeParticles()` | Position PDF/CDF, velocity distribution, charge or weights. | -| Time integration | `advance()` and `LeapFrogStep()` | Replace or add a time stepper while preserving particle migration and field solve ordering. | -| Particle-field transfer | `AlpineManager::par2grid()` and `grid2par()` | Add a deposition/interpolation method or solver-specific transfer path, with centering and conservation documented. | -| Diagnostics | `dump()` and `dumpLandau()` | Add conserved quantities, spectra, field norms, or particle statistics. | -| Load balancing | `LoadBalancer` and the `balance()` call site | Adjust thresholds, repartition cadence, or ORB policy. | - -Keep physics-facing changes explicit: document whether the change affects charge conservation, interpolation order, field centering, floating-point reproducibility, or MPI/GPU execution order. +| Problem geometry and BCs | `YourManager::pre_run()` | Domain extents, solver parameters, external fields | +| Initial particles | `initializeParticles()` | Position/velocity distributions, particle species | +| Time integration | `advance()` / stepper method | New integrator | +| Deposition and gather | `AlpineManager::par2grid()` / `grid2par()` | If you need to change the CIC interpolation | +| Output | `dump()` and helpers | Diagnostics and output | +