PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Future Architecture Specifications

This page indexes architectural work that is proposed rather than built, and records the dependency order between the pieces. It prevents design decisions from being lost between independently reviewed branches.

Being listed here is not a statement that a YAML or file format is accepted. The status column is authoritative: a specification is proposed until its own page says otherwise.

1. Status and Dependency Order

Specification Status Dependency
Field Identity and Layout Catalog implemented none
Field Statistics implemented field catalog
Field Statistics Planned Extensions proposed field statistics
Function Identity and Observability Specification deferred, benchmark-gated none
Immersed boundaries, moving bodies, moving frames (5. Immersed Boundaries, Moving Bodies, and Moving Frames) planned; switches refused none
Multi-block coupling (6. Multi-Block Coupling) planned; blocks other than 1 refused none
RANS closures (6a. RANS Closures) planned; rans block and -rans refused none
Pressure boundary conditions (6b. Pressure Boundary Conditions) planned; no selector exists boundary system
Newton-Krylov Jacobian types and modes (7. Newton-Krylov Jacobian Types and Modes) planned; refused at validation Newton-Krylov solver
Workflow Extensibility Guide proposed extension directions none

The typed field catalog established Eulerian and particle identities, layout metadata, and non-owning views over existing vectors without changing vector ownership. That is the correctness foundation statistics rely on for shifted, face-centered, and component-staggered fields, which is why it had to land first.

Field statistics build directly on it and are implemented; what remains proposed for that subsystem is indexed at Field Statistics Planned Extensions, which carries its own dependency order.

Proposed extensions to the conductor workflow - further grid geometries, grid-quality gates, sweep retry, convergence-based run completion, and data-driven particle closures - are collected at Workflow Extensibility Guide.

2. Rules Shared by Future Work

Future architectural work must:

  • use a separate branch for each reviewable phase;
  • inspect relevant implementation history before changing layout, periodic, I/O, restart, or monitoring behavior;
  • reuse existing setup, geometry, mask, field, I/O, logger, and postprocessing surfaces before adding a new implementation;
  • retain the high-level setup and run-loop shape unless a proven requirement makes a local orchestration change necessary;
  • add regression tests that fail without the intended change;
  • update public templates, configuration validation, ingestion documentation, runtime documentation, and developer documentation in the same phase; and
  • run the full serial, MPI, periodic, restart, postprocessing, ingress, and documentation gates before merge when those surfaces are affected.

Strings remain correct at true ingress and presentation boundaries. Runtime systems resolve them once into the typed identity appropriate to that system; PICurv does not use one universal ID namespace for fields, functions, boundary handlers, and postprocessing operations.

3. Statistics Direction

Field statistics are implemented. Windows accumulate numerically stable centered moments online, ride in the committed checkpoint bundle, resume on continuation, and are derived into Reynolds stresses, RMS, turbulent kinetic energy, and fluxes in post-processing. The contract is at Field Statistics.

The direction the remaining work follows is that averaging commutes with linear operations and not with anything else. Spatial reduction over accumulated pointwise state is exact after the fact, so profiles, regions, and bins are post-processing operations; only what the reduction cannot reach — the moment order, the choice of products, statistics of interpolated or nonlinear quantities, and conditional sampling — has to be resolved while the solver runs. The same reduction traversal could eventually serve the rolling physical-solution monitor, permitted only where tests demonstrate identical results. Existing logger formats and PETSc monitors are preserved throughout.

The proposed extensions and their dependency order are at Field Statistics Planned Extensions.

4. Function Identity Direction

Function logging/profiling identity is deliberately separate. It may replace repeated function-name scans with compile-time IDs or cached handles only after benchmarks show that the lookup overhead is material. It does not block the statistics pipeline. See Function Identity and Observability Specification.

5. Immersed Boundaries, Moving Bodies, and Moving Frames

Status: planned, not implemented. The legacy CURVIB code this solver descends from imposed immersed bodies on the curvilinear grid, moved them, and coupled their motion to the flow. None of that was ported. What reached this tree is the switches and some dormant plumbing:

  • models.physics.fsi.immersed and moving_fsi (-imm, -fsi), plus the passthrough-only -rfsi, -mframe, -rframe, -mhv and -lv;
  • a Poisson pre-solve branch for immersed cases (solid-aware restriction of Nvert through the multigrid hierarchy and a check for fully blocked regions), and Nvert solid markers that the momentum and Poisson kernels honour;
  • commented-out calls to ibm_interpolation_advanced, a function defined nowhere, in both momentum solvers and the flow-solver orchestration; and a commented-out moving-frame convection branch in ComputeRHS.

Each switch used to be accepted, and each ran a different problem without saying so: immersed reconfigured the Poisson solve around a body that was never loaded, moving_fsi did nothing, and -mframe/-rframe skipped the convective term altogether. They are now refused - the YAML switches by picurv validate, and the flags by CreateSimulationContext with PETSC_ERR_SUP - and tests/c/test_setup_lifecycle.c holds that refusal in place.

What must exist before any switch is accepted again. Loading a body surface and classifying cells against it into Nvert; the interpolation that sets velocity at the immersed-boundary nodes each stage, in every momentum solver that claims support; an end-to-end check that the dormant Poisson branch conserves mass around a real body; and, for moving bodies or frames, the motion model and the frame-relative convection term. The Newton-Krylov solver refuses all of these independently and would need its own treatment.

Design owner: the repository owner. Nothing here is scheduled.

6. Multi-Block Coupling

Status: planned, not implemented. The configuration and setup layers are multi-block aware: models.domain.blocks reaches -nblk, PICGRID files carry several blocks, boundary_conditions accepts one face list per block and stages a bcs file for each, and the solvers loop over blocks. What is missing is the coupling. Every inter-block exchange (Block_Interface_U) is commented out - in the explicit and dual-time momentum solvers and in the initial condition - and nothing couples the pressure solve across blocks, so a multi-block case was a set of isolated single-block solves that reported themselves as one domain. No test or shipped example ever ran one.

Validation now refuses blocks other than 1, and setup refuses -nblk other than 1.

What must exist before more than one block is accepted. Interface exchange of the velocity fields at shared faces in every momentum solver and in the initial condition; pressure coupling across blocks; particle hand-off between blocks; and a runtime harness showing that a domain split into blocks reproduces the single-block solution. The Newton-Krylov solver refuses multiple blocks independently. Field statistics payloads are already block scoped and follow the same natural ordering the Eulerian payloads do; the harness that proves multi-block equivalence should cover them at the same time.

Design owner: the repository owner. Nothing here is scheduled.

6a. RANS Closures

Status: planned, not implemented. PICurv models turbulence with the LES closures at LES Turbulence Closure; there is no Reynolds-averaged path. A k_omega selector existed until 2026-09-22 and was removed: nothing behind it was ever built. Setup allocated an eddy viscosity but never the K_Omega fields, the transport update in FlowSolver was commented out, and the function it called was defined nowhere, so a case that enabled it copied a null vector and aborted at the end of the first timestep. It was recorded known-defective on 2026-09-18 and, since no implementation had ever existed, returned to planned when the dead hooks came out. src/guide.md lists exactly what was removed.

models.physics.turbulence.rans is refused at validation, and -rans is refused at setup, so nothing is silently ignored.

What must exist before a RANS selector returns. Storage and ghost exchange for the turbulence variables; a transport equation for each, discretized on the same curvilinear metrics as momentum, with their production, dissipation and cross-diffusion terms; wall treatment matched to the closure, including which wall function is admissible with it; checkpoint and restart of the turbulence state; and a validation case with a reference profile - a channel at a published Re_tau - showing the mean profile and the eddy viscosity the closure is supposed to produce. A wall-modelled LES path is the nearer alternative for the same engineering questions, and the wall functions already exist.

Design owner: the repository owner. Nothing here is scheduled.

6b. Pressure Boundary Conditions

Status: planned, not implemented. No boundary handler sets pressure. Every non-periodic face - wall, inlet, and the conservation outlet - prescribes the normal velocity, and the pressure solve treats all of them as zero normal gradient by leaving the face out rather than by any stored value: the Poisson operator drops each boundary face's term (PoissonLHSNew() in src/poisson.c), the dummy rows are identities with a zero right-hand side, the projection corrects interior faces only (Projection()), and the constant null space is removed, so the pressure level is free. The conservation outlet's flux rescaling is what keeps that all-Neumann problem solvable.

UpdateDummyCells() fills pressure's dummy cells with the adjacent interior value. That matches the condition above and exists so that P_nodal and near-wall pressure gradients read consistent values; it is output hygiene, not a boundary condition the solve uses.

What must change together when a pressure condition is added. A Dirichlet face - a far field, or a pressure outlet at p_b - reaches four places, and setting the dummy value alone changes nothing the solve sees:

  • the Poisson operator keeps that face's term, with the correction's dummy value tied to the interior as phi_dummy = -phi_interior (the correction vanishes on the face, because p_b is fixed);
  • the constant null space is removed only when no face fixes the pressure level;
  • the projection corrects that face's flux from p_interior - p_dummy, which is where the stored dummy value 2 p_b - p_interior - the same form UpdateDummyCells() uses for velocity - is finally read; and
  • the face's velocity condition becomes an outflow the pressure drives, not a prescribed flux, so the conservation rescaling must not apply to it.

The existing surfaces are the place for it: the boundary handler system for the new face type and its parameters, UpdateDummyCells() for the dummy value, and the Poisson assembly and projection for the rest. Scaffolding without behavior already exists and should be completed rather than paralleled: the FARFIELD face type, the BC_HANDLER_FARFIELD_NONREFLECTING and BC_HANDLER_OUTLET_PRESSURE handler identities (no handler implements either), and a farfield priority stage in BoundarySystem_ExecuteStep() that today finds no handlers to run. None of the four can be settled in isolation, so the design is to be planned as one change, with a verification case - a channel driven by a pressure difference against its analytic flow rate - before a selector is exposed.

Design owner: the repository owner. Nothing here is scheduled.

7. Newton-Krylov Jacobian Types and Modes

Status: planned, not implemented. The Newton-Krylov solver's jacobian block is a discriminated configuration so that further constructions can be added beside the one that exists, type: finite_difference with mode: matrix_free. Two are designed; both are refused at validation until they exist.

A second finite-difference mode, colored_sparse, would assemble a sparse numerical Jacobian using coloring:

jacobian:
type: finite_difference
finite_difference:
mode: colored_sparse

Frozen-momentum approximations are a different Jacobian type, not storage modes of finite difference:

jacobian:
type: frozen_momentum_approximation
frozen_momentum_approximation:
structure: diagonal # or: full_sparse

Where each would be added is recorded with the solver's extension points at 9. Preconditioning Architecture and Status.

Design owner: the repository owner. Nothing here is scheduled.

8. Branch Policy

Specification-only work uses a documentation branch. Implementation begins only after explicit plan approval, from current main, and each completed phase is merged before the next phase branch is created. A later phase must not rely on unreviewed changes in another long-lived branch.