Training Pipeline¶
Problem → Domain → Model → Physics → Solver → Backend → Metrics.
Each arrow is a real, swappable API boundary — not just a diagram. This page shows the same pipeline at two levels: the explicit building blocks, and the one-call convenience wrapper built on top of them.
Building it explicitly¶
from pinneapple_physics import get_preset, compile_physics
from pinneapple_design import build_domain, sample_domain
from pinneapple_neural import build_model, train_model
# 1. Problem — what to solve
spec = get_preset("burgers_1d", nu=0.01)
# 2. Domain — where to sample (only needed if you're not using the
# preset's own domain_bounds directly, e.g. for a custom geometry)
domain = build_domain("channel_2d")
x_int, x_bnd = sample_domain(domain, n_interior=4096, n_boundary=512)
# 3. Model — coordinates -> fields
model = build_model("SIREN", in_dim=2, out_dim=1, hidden_dim=64, n_layers=4)
# 4. Physics — residual + constraint losses, compiled from the spec
losses = compile_physics(spec)
# 5. Solver — training policy (Adam, single stage, here)
result = train_model(model, losses, epochs=5000)
# 6. Backend — which runtime executed the above (PyTorch by default;
# pinneapple_tools.compute_backends.set_backend("jax") switches it)
# 7. Metrics / Researcher — compare, log, and validate the result
Each numbered step maps onto one of the Core Concepts pages; swapping any one component (a different preset, domain, architecture, trainer, or backend) does not require touching the others.
The top-level pinneapple convenience package¶
import pinneapple as pp re-exports the pieces most used at the start of an
experiment — pp.get_preset/pp.list_presets/pp.register_preset (step 1)
and pp.build_model (step 3) are real top-level wrappers over the same
pinneapple_physics/pinneapple_neural functions used above. It does
not currently wrap steps 4–5 (physics compilation / training) — for
those, import compile_physics/train_model from pinneapple_physics/
pinneapple_neural directly as shown above.
pp.quickstart(problem_id, **problem_kwargs) is a summary helper, not a
full pipeline run: it loads the named preset and prints its PDE kind,
fields, coordinates, domain bounds, conditions, and configured solver, then
returns the ProblemSpec — useful as a first sanity check on a preset
before writing the explicit pipeline above, but it does not sample a
domain, train a model, or produce a visualization by itself.
Where each stage can diverge from this default path¶
- Problem: hand-build a
ProblemSpec/ProblemBuilderinstead of a preset — see ProblemDefinition. - Domain: use a CSG/SDF-composed or mesh-based domain instead of a built-in one — see Geometry & Domain.
- Physics: use
SymbolicPDEfor a PDE with no built-inkind, orDoMINO/SubdomainPINNfor domain decomposition — see PINN / Physics. - Solver: use
TwoPhaseTrainer,TimeMarchingTrainer,CausalPINNTrainer, orDDPPINNTrainerinstead of the defaultTrainer— see Solver. - Backend: switch to JAX for the residual computation — see Backend.
- Metrics / Researcher: run the trained model through
Arena/PINNArenaBenchmarkinstead of inspecting it standalone — see Researcher & Benchmarking.
Physics-native data: PhysicsDataset, DataLoader and samplers¶
pinneapple_core.data serves a PINN, a neural operator and an inverse problem through one loader. A DataLoader takes
sources, each a PhysicsDataset (labelled arrays, shuffled and batched) or a sampler (points drawn on demand), and yields a
Batch with one group per source.
from pinneapple_core.data import BoundarySampler, CollocationSampler, DataLoader, PhysicsDataset
loader = DataLoader({"col": CollocationSampler(geom, "lhs"), "bc": BoundarySampler(geom), "obs": PhysicsDataset(x_obs, u_obs)},
batch_size={"col": 1024, "bc": 128, "obs": 16}, steps=2000)
for batch in loader:
x = batch["col"]["x"] # requires_grad is already set
| Sampler | Draws |
|---|---|
CollocationSampler(domain, "uniform" / "lhs" / "sobol") |
interior points of a Domain, Geometry or {coord: (lo, hi)} box |
BoundarySampler(geometry, part=None) |
boundary points with outward normals; part="x_max" for a named boundary |
MeshSampler(mesh, "nodes" / "cells" / "random") |
nodes, cell centres, or uniform random points inside cells |
TrajectorySampler(states, n_in, n_out, stride) |
windows of time series, x the past and y the future |
AdaptiveSampler(base, residual_fn) |
a pool resampled with probability proportional to the PDE residual (mixed with some uniform) after loader.update(model) |
ActiveSampler(base, score_fn) |
the top-scoring candidates of an acquisition function, for choosing the next expensive run |
With a dataset as the first source and no steps, one iteration is one epoch. physics_aware=True (default) sets
requires_grad on the points of collocation, boundary and adaptive sources, converts to dtype/device, and adds the
coordinate names to batch.meta. Seeds make every stream reproducible. examples/data_api/01_pinn_operator_inverse.py trains
a Poisson PINN (relative L2 error 1.6e-3), an operator for -u'' = f (5.3e-2) and an inverse problem for the diffusivity
(kappa = 1.992, true 2) from this one API. The older pinneapple_data loaders and pinneapple_neural.trainer samplers are unchanged.