Skip to content

Results, Batch Simulation, and Learning Data

One Result Contract

results.SimulationResult is the scientific result of one analysis. It can hold:

  • scalar or fixed-shape quantities of interest;
  • live finite-element fields and field-artifact links;
  • time/load/iteration histories;
  • solver and model metadata;
  • visualization, checkpoint, and report artifacts.
  • a scientific verification report and explicit trust level.

XDMF, CSV, and NumPy files are artifacts, not the result abstraction itself. This distinction lets one solve feed visualization, a campaign, a report, or a training dataset without each consumer reverse-engineering output files. write_manifest(...) records artifacts inside the manifest directory with relative paths by default, so moving one complete result directory does not break its links. It also adds a deterministic provenance seal over the result record and every registered artifact. Run agentfem verify result.json to detect a partial copy, replaced HDF5 payload, or edited manifest. This integrity check is deliberately separate from scientific verification; see docs/provenance_seal.md.

For frozen runtime locks, serializable loading bases, campaign-backed response operators, and threshold-event localization, continue to docs/scientific_experiments.md.

Linear problems, engineering AnalysisStep objects, and nonlinear problems provide solve_result() while preserving the older solve() field-return contract.

Linear solve_result() records PETSc KSP reason, iteration count, and residual norm. It no longer infers convergence merely because the Python call returned. The result can consume that evidence through a low-ceremony policy:

solved = step.solve_result()
solved.add_quantity("maximum_displacement", max_u, unit="m")
solved.verify(
    "engineering",
    required_quantities=("maximum_displacement",),
).require()

One execution evidence stream

Standard nonlinear, explicit, implicit-dynamic, first-order transient, and J2 steps emit the same JSON-safe SolveEvent contract. The terminal, optional .sta status file, result histories, and complete manifest trace are views of that one stream. print_every changes only human display cadence: every accepted time increment remains in result.metadata["execution"], while cutbacks and failed attempts remain auditable rather than being filtered out.

This is important for both reproducibility and AI operation. An agent does not infer convergence by scraping prose, and a human does not receive a simplified story that differs from the machine record. Stateful J2 owns its quadrature state, while heat, Explicit dynamics, and Standard dynamics share one transient checkpoint envelope. CheckpointRecord makes every schema and portability boundary visible without pretending a partition-bound checkpoint is portable.

Transient heat, Explicit dynamics, and Standard dynamics also share one-call field output:

result = step.solve_result(output="results.xdmf")

The returned result owns the accepted-time evidence and references both the XDMF index and HDF5 heavy data. Heat writes temperature by default; structural dynamics writes displacement, velocity, and acceleration. Supplying fields=(...) replaces that default catalog. Request output on the first solve or when resuming an incomplete checkpoint. A resumed output is marked continuation_segment with its physical start time. AgentFEM refuses to fabricate missing intermediate frames after a step has already completed.

The three transient procedures can also pause and resume with the same public contract:

step.run(until_step=50)
checkpoint = step.save_checkpoint("restart/step-50")

resumed = build_the_same_step()
resumed.load_checkpoint(checkpoint)
result = resumed.solve_result(output="restart/continuation.xdmf")

The checkpoint records current fields, accepted time, algorithm identity, execution events, diagnostic histories, mesh/function layout, and one state shard per MPI rank. Version 2 uses atomic publication, generation-specific shards, and per-shard integrity checks. It intentionally requires the same mesh partition and MPI size. This is useful restart today and a precise boundary for the future global-cell identity needed by cross-partition restart.

Dynamics results carry kinetic energy and, when the step exposes a linear stiffness operator, recoverable strain and total mechanical energy. Transient heat carries thermal_content = 1^T C T. These are sampled from the same engineering operators consumed by the solution procedure and survive restart.

Field output versus history output

AgentFEM follows the established finite-element distinction:

  • field output is a spatial field over a mesh at selected frames;
  • history output is a frequently sampled scalar/vector/tensor at a small region, probe, control node, or global integral;
  • quantities of interest are named values selected for reports, campaigns, verification, or learning datasets.

SimulationResult.add_quantity and add_history construct an already computed scientific result. They are not output-request syntax. Batch forms add_quantities(mapping) and add_histories(axis, mapping) avoid repetitive calls. A field-output request is declared before export:

request = results.field_output(
    "U", "S", "E", "EVOL",
    every=1,
    configuration="deformed",
    backend="xdmf",
)
artifacts = request.write_finite_strain(
    "output",
    domain=domain,
    snapshots=step.snapshots,
    material=material,
)

The field catalog owns aliases and physical meaning. In a finite-strain context, E resolves to LE; GREEN requests Green--Lagrange strain explicitly. This keeps short engineering vocabulary without allowing one name to silently change tensor meaning.

One compact scientific and presentation series

AgentFEM's serial static-solid and finite-strain result paths write one temporal .xdmf index and one compressed .h5 heavy-data store. Topology is stored once. Each frame contains:

  • its load/time value;
  • coordinates x + scale*u;
  • nodal U and UMAG;
  • every requested cell field on that same grid.

ParaView therefore opens one source, finds the time axis, animates the actual deformed geometry, and switches among all fields without a Warp filter or multi-block selection. The HDF5 store also retains the reference coordinates, so the directly viewable result does not discard finite-element provenance. deformation_scale=1 is the physical configuration; another value is explicitly a presentation scale.

Ordinary static output retains reference coordinates and exposes U as point data, so Warp By Vector produces one deformed geometry with every cell and point attribute attached. Finite-strain presentation output can instead store x + scale*u directly when requested. SimulationResult.metadata.field_output records the backend, layout, and geometry convention. For a two-dimensional model, the finite-element unknown remains the physical vector (Ux, Uy), while the visualization dataset stores U=(Ux, Uy, 0) on XYZ geometry. ParaView can therefore select U directly as a three-component Warp vector. The result contract records physical_components=2, stored_components=3, both model and storage geometry dimensions, and the semantic alias Displacement -> U; no duplicate displacement array is written.

The low-level io.XDMFTimeSeries mirrors DOLFINx and may expose one XDMF Grid per Function. It is an expert compatibility API, not the normal result path. Prefer step.solve_result(output=...): serial static and transient analyses write the compact single-grid XDMF/HDF5 layout. Under MPI, AgentFEM retains the collective XDMF/HDF5 scientific record and also registers a fields_paraview PVD artifact whose time steps each contain one geometry with all point and cell fields. The normal ParaView workflow therefore does not require Extract Block or Append Attributes. The machine-readable field_output.recommended_visualization_artifact points to the compact XDMF in serial and to this PVD in MPI; visualization_requires_extract_block is therefore false even though the collective scientific XDMF retains DOLFINx's grid-per-field organization.

Static balance evidence also fails closed. Strong Dirichlet reactions use the unconstrained assembled residual, but MPC, weak, contact, projection, and multiplier constraints require provider-owned dual forces. When any declared constraint lacks that channel, SimulationResult records static_equilibrium.status = unavailable and a constraint_balance_contract instead of publishing a partial reaction sum as a complete equilibrium check. A provider closes force balance only by supplying both its generalized dual and the corresponding physical-space resultant; it closes work only by also supplying the accepted work-conjugate coordinate. The constraint provider itself may expose dual_evidence(problem) after convergence. AgentFEM collects and validates those named records before the common ledger consumes them. AnalysisStep.constraint_dual_provider remains only as a compatibility bridge for older internal providers; new enforcement backends should keep extraction beside the assembly that defines the dual. A provider cannot promote completeness with a Boolean flag alone.

The exact affine periodic provider is the first native implementation of this contract. It evaluates the generalized reaction from the full unconstrained residual and the affine path tangent,

\[ Q_\lambda = \mathbf{R}_{\mathrm{full}}\!\cdot \frac{\partial\mathbf{u}_{\mathrm{aff}}}{\partial\lambda}, \]

and reports the component-wise physical resultant from the same displacement residual. For a homogeneous periodic cell this is checked against \(V\,\mathbf{P}:\partial\mathbf{F}/\partial\lambda\). The nonlinear endpoint does not pretend that one force--coordinate pair is the complete work. Instead, the affine problem records accepted \((Q_\lambda,\lambda)\) samples, persists them through checkpoint/restart, and publishes their trapezoidal integral as affine_constraint_path_work. This path work is independently checked against the Hill--Mandel macroscopic work for periodic J2 cells. At a kink in a non-proportional deformation history, the result retains both affine_path_generalized_reaction (incoming) and affine_path_outgoing_generalized_reaction (right-sided). The work on each increment therefore uses that increment's own deformation-gradient tangent.

The first bounded contact implementation applies the same ownership rule. A fixed-rigid-plane penalty provider assembles its own conservative potential, residual, and consistent tangent, then reconstructs the converged nodal reaction and MPI-global resultant from that exact operator. Results also record contact energy, penetration norm, and active contact measure. Contact energy is internal system energy; it is not added again as prescribed-motion work. The ordinary nonlinear Procedure now retains force--coordinate samples only at accepted stations and reports constraint_path_work separately. For a fixed obstacle its conjugate translation is identically zero, hence obstacle work is exactly zero even when contact energy is nonzero. Overall static_work.status remains unavailable until natural-load work and internal energy histories close the complete nonlinear balance; failed cutback trials never enter either claim.

Exact rectangular periodic MPC construction has a separate, narrower diagnostic contract. periodicity.diagnostics() reports globally owned slave DOFs, ghost copies, master relations, unmatched or multiply matched slaves, coefficient validity, participating ranks, periods, and coordinate tolerance. This proves that the elimination graph was constructed consistently; it does not reconstruct eliminated multipliers, face-reaction distributions, or a macroscopic work coordinate. Those balance channels therefore remain fail-closed until the numerical provider supplies their actual dual evidence.

XDMF is the small XML description and HDF5 is the compact numerical payload. Inlining millions of values into XML would produce a much larger and slower file, so the pair should be treated as one logical result dataset. The optional backend="pvd" and "both" modes remain available for tools that specifically require PVD/VTU, but they are no longer the default.

Quantities of Interest

results.integral, results.average, and results.l2_norm assemble physical expressions with MPI reduction. SimulationResult.add_dof_statistics(...) captures coefficient extrema and counts for quick inspection; those values are explicitly not physical domain integrals.

solved = step.solve_result()
solved.add_dof_statistics(u, prefix="u", unit="m")
solved.add_quantity(
    "mean_temperature",
    results.average(T, measure=dx),
    unit="K",
)
solved.add_quantities({"mean_temperature": mean_T, "heat_flux": total_flux})
solved.write_manifest("result.json")

For cell or constitutive data, coefficient extrema are not enough. Pass the resolved scalar values together with their physical cell or quadrature weights to obtain an exact volume-weighted distribution:

statistics = results.weighted_field_statistics(
    mises,
    integration_weights,
    quantiles=(0.05, 0.5, 0.95),
    thresholds=(yield_stress,),
    location="quadrature_points",
    representation="raw_constitutive_values",
    comm=domain.comm,
)

The returned record distinguishes raw integration-point values from cell averages or recovered nodal fields and states the quantile and threshold definitions. MPI ranks receive the same summary. The weights are explicit: AgentFEM does not infer a physical volume distribution from arbitrary field coefficients.

QuadratureField.weighted_statistics(...) supplies those weights from the reference quadrature rule and absolute geometric Jacobian. Only owned cells contribute under MPI; ghost cells are excluded. Tensor fields require an explicitly selected component or invariant, so the API never invents a scalar meaning.

The full definitions, measure convention and references are collected in RVE homogenization and physical field statistics.

Periodic-cell evidence at every accepted increment

results.periodic_cell_history(periodicity) is an online scientific request, not merely a postprocessor over saved XDMF frames. It records a lightweight macroscopic state after every accepted affine increment while spatial fields may be saved less often:

output = results.output_plan(
    "output/rve",
    field=results.field_output("U", "S", "E", every=5),
    requests=(results.periodic_cell_history(periodicity),),
)

If twenty increments are accepted, the CSV and NPZ contain the initial state plus all twenty accepted states even though the spatial result contains only the requested sparse frames. The recorder retains macroscopic tensors and one preceding microscopic state, rather than accumulating all finite-element fields in memory.

Each accepted macro row also carries its actual increment size, Newton iteration count, final residual, periodic-equation mismatch and accepted attempt number. This places cutback and convergence evidence beside the state it qualifies instead of requiring a later join against terminal logs.

For Cauchy stress \(\boldsymbol\sigma\), AgentFEM uses

\[ \eta = \frac{\sigma_m}{\sigma_{\mathrm{vM}}},\qquad \bar\theta = 1-\frac{2}{\pi} \cos^{-1}\!\left(\frac{27J_3}{2\sigma_{\mathrm{vM}}^3}\right). \]

The normalized Lode parameter is +1 in axisymmetric tension, 0 in pure shear and -1 in axisymmetric compression. Both quantities are undefined when the deviatoric stress vanishes. Structured results therefore carry homogenized_stress_state_defined; a numerical placeholder is never evidence that a hydrostatic state's triaxiality or Lode angle exists.

For two consecutive accepted compatible states, the finite-strain macrohomogeneity audit compares the same trapezoidal first-Piola work at both scales:

\[ \Delta w_\mu = \frac{1}{|\Omega_0|} \int_{\Omega_0}\frac{\mathbf P_n+\mathbf P_{n+1}}{2}: (\mathbf F_{n+1}-\mathbf F_n)\,\mathrm dV, \]
\[ \Delta w_M = \frac{\overline{\mathbf P}_n+ \overline{\mathbf P}_{n+1}}{2}: (\overline{\mathbf F}_{n+1}-\overline{\mathbf F}_n). \]

The result records both work densities, their signed residual and relative error. This is a quasistatic periodic/affine Hill--Mandel contract; it does not silently omit body-force or inertia power from a problem where those terms are present. The macro stress remains normalized by the complete reference-cell volume, so void volume carries zero stress rather than changing the result to a matrix-phase average.

Point and path probes

Field values at physical coordinates use the same MPI-safe interface in serial and distributed runs:

tip_u = results.probe(U, at=(length, height / 2))
temperatures = results.sample_points(
    T,
    ((0.0, 0.0), (0.5, 0.0), (1.0, 0.0)),
)
centerline = results.sample_path(
    T,
    start=(0.0, height / 2),
    end=(length, height / 2),
    count=101,
)
centerline.add_to(
    solved,
    name="centerline_temperature",
    unit="K",
    distance_unit="m",
)

AgentFEM locates owned cells, chooses one deterministic MPI owner for each point, and returns the same ordered values on every rank. All ranks must request identical coordinates. Missing points raise by default; missing="nan" is an explicit alternative for exploratory sampling. For a discontinuous field, a point exactly on an interelement boundary has a side ambiguity, so place the probe inside the intended cell when a one-sided value is required.

Standard stress and strain fields

Model-generated static elasticity now provides its standard fields in one call:

result = step.solve_result(output="solid.xdmf")
# result.fields contains Displacement, S, E, and MISES

# Opt in to a diagnostic field set when the analysis needs it.
energy_result = step.solve_result(
    output="solid_with_energy.xdmf",
    field_variables=("S", "E", "MISES", "SENER"),
)

Small-strain elasticity uses one reusable projection path. Application code normally requests it through the step so field creation and single-grid output remain one transaction:

solid_result = step.solve_result(
    output="solid.xdmf",
    field_variables=("S", "E", "MISES", "SENER"),
)

The available standard names are S, E, MISES, and SENER. The engineering default is U/S/E/MISES: U is the primary unknown, S/E are standard mechanics fields, and MISES is materialized for immediate plotting even though it is derived from S. SENER is opt-in because a per-cell energy density is primarily diagnostic; total strain energy and energy closure belong in compact histories or verification quantities.

The default derived-field representation is a global L2 projection onto discontinuous DG0, hence a cell average rather than an arbitrary centroid value. It is not an integration-point dump, nodal extrapolation, or smoothed nodal field. No values are averaged across neighboring cells or material interfaces. Each FieldResult.processing record preserves this distinction. In plane strain, Mises stress includes the constitutively implied out-of-plane stress. The lower-level results.project(...) remains available for reviewed UFL expressions and higher-order discontinuous output spaces.

For regional materials, results.small_strain_partition_fields(...) assembles one global projection from (material, region) contributions. It preserves a single field over the original mesh rather than writing one incomplete field per material.

results.reaction_resultant(problem, on=support, component=0) reports the MPI-global residual resultant on one named strong-Dirichlet boundary. Omitting on retains the whole-field sum. Affine MPC, weak, and contact reactions deliberately require separate definitions. For proportional linear loading, diagnostics.linear_static_energy(...) reports strain energy, external work, and their closure. results.static_work_balance(...) extends that contract to non-zero strong prescribed motion by integrating the conjugate reaction along a proportional path. Ordinary model-generated static solid results record natural-load work, prescribed-motion work, total external work, strain energy, and their closure automatically.

Affine MPC reactions must be defined from the dual of the reduced constraint or from a declared macro-motion mode; summing eliminated slave residuals is not invariant to the chosen elimination graph. Weak-constraint reactions are consistent boundary tractions/fluxes from the weak form. Providers that can extract these values publish a ConstraintDualEvidence record through the shared protocol. A provider that cannot do so remains explicitly incomplete; AgentFEM then marks its force or work balance unavailable instead of applying the strong-Dirichlet formula.

A model-generated linear static solid also records force equilibrium without extra application code:

result = model.step(target=displacement).solve_result()
result.quantities["external_force_resultant"]
result.quantities["reaction_force_resultant"]
result.quantities["force_balance_residual"]
result.quantities["relative_force_balance_error"]

The external resultant is assembled from the same complete right-hand side used by the solver; it therefore includes all body and boundary contributions in F. The reaction is the unconstrained residual at strong Dirichlet dofs. The metadata states this scope explicitly. Provider-owned result paths may add MPC, weak-constraint, or bounded-contact reactions only when the assembling provider supplies the matching physical-space resultant.

Structured observation grids

A common physical grid separates a learned field representation from the FEM mesh used by each case:

grid = surrogates.regular_grid(
    bounds=((0.0, length), (0.0, height)),
    shape=(128, 64),
)
sample = datasets.fem_observation_sample(
    U,
    grid,
    name="displacement",
    unit="m",
    components=("U1", "U2"),
    outside="mask",
)
sample.write("displacement_grid.npz")

The export records physical axes, array order, component layout, units, mesh-independence policy, and an optional inside-geometry mask. It is MPI-safe and uses the same coordinates for every case. This is a real data-preparation path for structured-grid neural operators; model architecture and training remain external responsibilities.

An external solver protocol can request the same geometric operation without constructing a learning dataset:

sample = results.sample_rectilinear_grid(
    U,
    bbox=(0.0, length, 0.0, height),
    shape=(128, 64),
    reduction="magnitude",
)

image = sample.values   # array order: (ny, nx)
inside = sample.inside  # false for points outside a non-rectangular mesh

For three dimensions, shape=(nx, ny, nz) produces (nz, ny, nx). Domain exterior values are NaN and the explicit mask is authoritative. The routine is MPI-safe and uses the same ownership rules as point probes.

Scientific field datasets

ScientificDataset remains the compact contract for parameter-to-quantity surrogates. Function-to-function learning uses a distinct collection so a field is never flattened until a selected trainer explicitly requests it:

field_dataset = datasets.ScientificFieldDataset(
    case_ids=case_ids,
    encodings=(source_encoding, temperature_encoding),
    fields={
        "heat_source": source_fields,       # (case, channel, nx, ny)
        "temperature": temperature_fields,
    },
    parameters={"source_amplitude": amplitudes},
    case_metadata=case_evidence,
)

split = field_dataset.split(
    validation_fraction=0.2,
    test_fraction=0.1,
    seed=2026,
)
field_dataset.write("heat_operator_dataset")

The manifest retains every field's role, unit, components, representation, geometry policy and per-case shape. All arrays share a leading case axis; content hashes cover fields, parameters, coordinates, masks, case IDs and metadata. Reload refuses modified data whose fingerprint no longer matches. The built-in compressed NPZ storage is deliberately a small, portable reference backend. Large chunked storage can implement the same contract without changing a trainer or the scientific specification.

Campaign fields enter the same contract through one explicit extractor rather than a project-owned loop over result folders:

assembler = datasets.FieldDatasetAssembler(
    encodings=(load_encoding, displacement_encoding),
    parameter_names=("hole_radius", "load"),
    extract=lambda case, outcome: datasets.FieldCaseData(
        fields=read_case_fields(outcome.artifacts),
        coordinates=read_case_coordinates(outcome.artifacts),
        metadata={"mesh_family": "registered_plate"},
    ),
)

field_dataset = report.require_field_dataset(
    assembler,
    quality="engineering",
)

The extractor owns the scientific mapping from one solver result to declared fields. AgentFEM owns accepted case identity, partial-failure policy, quality gates, parameter values, field-shape consistency, provenance and artifact links. It never guesses a field from a filename or silently promotes a failed case into training data.

Campaign to Dataset

A campaign evaluator may return:

  • a mapping of declared outputs;
  • campaigns.CaseOutcome with provenance/artifacts;
  • or a SimulationResult.

In the last case AgentFEM extracts only the declared QoIs into the scientific dataset. A fixed-length result history is also an ordinary dataset output when the output contract explicitly declares kind="history" and its complete shape. AgentFEM records the shared coordinate, coordinate unit, and content fingerprint in dataset metadata. It rejects successful cases whose arrays have the same shape but different coordinates: resampling is a scientific decision, not an implicit storage operation. Live DOLFINx fields are not serialized into table columns; their artifacts remain linked.

campaign = campaigns.create(
    name="material_trajectories",
    parameter_space=space,
    outputs=(
        datasets.Quantity("stress", shape=(n, 3, 3), kind="history"),
        datasets.Quantity(
            "equivalent_plastic_strain", shape=(n,), kind="history"
        ),
    ),
    evaluate=lambda parameters: build_material(parameters)
        .history(shared_path)
        .solve_result(),
    scientific_inputs={"loading_path": shared_path},
)

This is the same Campaign path used by finite-element simulations. There is no second material-data runner, and the campaign never changes the loading path or constitutive update.

Campaign configuration can be written as safe JSON for parameter definitions, sampling, output contracts, and execution policy. Python still supplies the trusted model builder/evaluator. The JSON file never imports or evaluates arbitrary code.

The runner supports serial execution, spawned local processes across independent cases, and MPI participation within one FEM case. Use campaigns.local_processes(workers=...) for a local parameter sweep. It does not use Python threads or fork an initialized numerical process, and it cannot be nested inside a within-case MPI communicator. Use deterministic plan shards for schedulers or separate MPI jobs.

Campaigns may receive scientific_inputs={...}. Source meshes supplied as Path objects are hashed by content; materials, loads, procedures, and observer plans use their public IR/summary contracts. Opaque objects make coverage incomplete. After a refinement campaign, use convergence.audit(...) to issue an observable-aware multi-axis certificate rather than inferring convergence from a successful solve or a plotted curve.

For a single analysis, call simulation.add_scientific_inputs(mesh=Path(...), material=..., loading=...) before write_manifest(...). This stores the same content-addressed input record directly in the SimulationResult; it does not replace runtime, artifact-integrity, convergence, or validation evidence.

Before training, require reviewed campaign evidence:

dataset = report.require_dataset(
    minimum_samples=4,
    quality="engineering",
)
training = surrogates.train(
    dataset,
    estimator=surrogates.RidgeSurrogate(),
    validation_fraction=0.2,
    seed=2026,
)
guarded = training.guard(fallback=run_high_fidelity_case)

require_dataset() rejects a partial campaign by default. A quality preset requires each sample to carry an accepted result assessment and records the dataset admission decision. The lower-level minimum_trust_level remains available when a project deliberately supplies its own evidence policy. Failed simulations are not silently discarded before learning; the caller must review them and set allow_partial=True deliberately. That acceptance and the failed case IDs are retained in the returned dataset metadata. surrogates.train(...) keeps the reproducible split, trained estimator, independent validation, and applicability guard together. The same protocol accepts the built-in transparent baselines or the optional PyTorch MLP adapter.

For direct PyTorch training without an AgentFEM trainer:

bundle = dataset.to_torch()
loader = bundle.loader(batch_size=64, shuffle=True)

AgentFEM owns names, units, shapes, provenance, splitting evidence, validation, and applicability. PyTorch owns tensors, modules, automatic differentiation, optimizers, and training loops.

Next Result Priorities

Campaign output directories include audit.json. The audit compares the immutable plan, case records, successful dataset identities, and declared file artifact hashes. A missing or modified artifact invalidates resume instead of being silently accepted. CampaignReport.audit() and write_audit() expose the same contract without rerunning a case.

  1. physical dual extraction for rectangular MPC, weak, and contact providers;
  2. nodal smoothing and higher-order stress recovery beyond implemented DG projection;
  3. natural-load, weak-constraint, affine-MPC, and broader transient work/energy histories beyond the current strong-displacement J2 history;
  4. cross-partition MPI restart identity and checkpoint retention policies;
  5. graph and basis-coefficient field encodings for unstructured neural operators;
  6. scheduler executors that preserve identical case records.