Skip to content

Lean projects and trusted user materials

case.py owns the engineering problem. A project does not need its own compiler cache, time-integration loop, checkpoint handler or connectivity writer.

Executing an existing Step

from agentfem import project

context = project.current_run()
step = model.step(target=u, dt=dt, steps=steps, checkpoint=checkpoint_policy)
report = project.execute_step(
    step, context=context,
    policy=project.RunPolicy(until_step=100, journal_every=10,
                             progress_every=100, export_partial=True),
    metadata={"experiment": "reviewed study"},
)

This optional operational wrapper serves the existing serial transient Step families. Ordinary short cases can still call step.solve_result() directly. The wrapper does not build a Model, choose a numerical method, change the time grid or adjust mass. Scheduled checkpoints remain declared on model.step. Progress, accepted history journals, a final checkpoint, execution status and failure reporting use existing contracts.

RunPolicy.restart restores through the Step's normal identity checks. A new run directory is required. Completed paths publish a SimulationResult; partial paths remain paused, not completed results. A wall limit is checked after accepted increments and raises a recorded failure with an attempted accepted checkpoint. It is not a hard process timeout. Use the CLI's process timeout for unresponsive processes. The wrapper currently rejects MPI rather than inventing collective file-writing behavior.

Optional observations={name: callback} receives the accepted Step and writes a sampled observation journal. Observations must be pure and JSON-safe. export(step, directory) returns named artifact paths. It runs at completion, or at a partial endpoint if explicitly requested. An export failure remains a failed delivery, with the accepted checkpoint retained; it does not erase the numerical state or silently publish a completed result. Timing in report.json covers Step execution and final export, not model construction or compilation.

For long complete histories, RunPolicy(history_storage="npz") keeps a compact result JSON with a lossless binary companion. It changes only publication, not accepted samples or restart state. See history storage.

Accepted material output

from agentfem import results

artifacts = results.export_accepted_response(
    step, directory,
    state_fields={"damage": ("history", 3)},
    units={"stress": "Pa", "displacement": "m", "time": "s"},
)

This bounded serial, one-material-point-per-cell route consumes accepted_material_fields(). The caller explicitly identifies state-variable meaning and components; there is no hard-coded damage column in core. Output contains one standard visualization dataset, the complete raw accepted state, cell keys, stress and gradient, and metadata. Invalid selectors and existing output files are rejected. No field is silently smoothed or averaged across an interface. Source labels, mesh provenance and physical units remain project assets; cell input identity is not a source file's element label.

One visualization entry point

For an animation, keep the endpoint in the same series instead of exporting a second visualization of it:

frames = results.AcceptedResponseSeries(
    context.output_directory / "results.xdmf", storage="frame_files",
    state_fields={"damage": ("history", 3)},
)
report = project.execute_step(
    step, context=context,
    policy=project.RunPolicy(field_intervals=40),
    frames=frames,
    export=lambda accepted, directory: results.export_accepted_response(
        accepted, directory, visualization=False,
    ),
)

Open results.xdmf in ParaView and select a time station; while a run is active, the last station is its latest published accepted frame, not necessarily the final state. The explicitly selected frame_files backend closes each immutable frame before atomically updating the index, so readers need not open a file currently being written. Keep results-data/ beside its XDMF index; the directory holds one shared mesh and the frame arrays, not additional visualizations to open. The older single_file backend remains available and is still the API default. See live output and restart segments.

accepted_material.npz preserves the full raw terminal material state; it is not a restart checkpoint. The archive-only option creates no second XDMF/HDF5 pair. Existing endpoint-only callers retain their default. The series reuses a checked cell-identity mapping and DG0 spaces, never field coefficients: each frame remains a detached, unsmoothed snapshot.

report.json identifies the primary visualization and separates restart, initial fields, advancement, accepted callbacks, terminal checkpoint, terminal fields/export and publication times. Advancement includes callbacks and scheduled checkpoints; the callback-subtracted figure still includes scheduled checkpoints and is not a pure solver-kernel time. These timings exclude model construction and material compilation before execute_step, and the final report write. Use process elapsed time for end-to-end comparisons.

Trusted native source bundles

# material/material.toml
schema = "agentfem.native-libraries.v1"
files = ["law.f90", "parameters.inc"]
include_directories = ["."]
flags = ["-O3", "-fno-fast-math", "-ffp-contract=off", "-fPIC", "-shared"]

[targets]
response = ["law.f90"]
from agentfem import constitutive

bundle = constitutive.build_native_libraries(
    "material/material.toml", cache_directory=".agentfem/material-build",
    trusted=True,
)
library = bundle.library("response")

Explicit trust is required: native source is executable code, not safe data. This is build infrastructure, not a new material ABI. Use compile_vumat for the supported legacy VUMAT transport; use a reviewed provider for other ABIs. The builder supports GNU Fortran on macOS/Linux/WSL2, snapshots declared inputs, records flags and compiler identity, locks cache publication, verifies library hashes on reuse, and retains failed-build logs. It never installs a compiler, downloads code or modifies the environment. Declare source/include dependencies; unsupported flags or undeclared Fortran includes fail before compilation.

Two generic arithmetic sources can be supplied by the installed distribution:

[bundled_sources]
"polar.f90" = "polar_series.f90"

[targets]
polar = ["polar.f90"]

polar_series.f90 and polar_wider.f90 implement guarded linear-right-stretch path integration, with different fast-admission radii and the same residual checks. CompiledCorotationalIncrement(bundle, "polar") repairs rejected points through the reference polar_strain_increment before publication. Neither is a universal interpretation of a vendor's VUMAT strain increment. An application must explicitly choose and bind its kinematic convention. Private material formulas, state layout, domain restrictions and specialized fusion adapters remain outside core.

Compatibility without private-module probing

Declare an installed-software requirement in the project configuration:

[project]
name = "my-study"
entrypoint = "case.py"
requires_agentfem = ">=0.4.3"
requires_api = [
  "constitutive.StrainHistoryRuntime",
  "results.AcceptedResponseSeries",
  "results.export_accepted_response(visualization)",
]

Project checks and the CLI run admission validate this constraint without executing the case. This is minimum software compatibility, not a reproducibility lock. Freeze runtime identity and scientific inputs separately for reviewed runs. Moving code from a project into the library changes implementation identity: retain the old environment for old checkpoints or start a fresh run; do not remove restart guards to make old archives load.

requires_api optionally names public AgentFEM attributes. It catches missing interfaces in older builds that share a development version, before executing case.py. It imports the named AgentFEM modules but does not call the attributes. The optional (keyword) suffix requires an explicitly named keyword-capable parameter in the callable's signature. It is a declaration, never evaluated Python: defaults, calls and multiple arguments are not accepted. A generic **kwargs alone does not prove support. This catches older exporters before a long solve, rather than failing only at final output. Presence/signatures still do not prove semantic compatibility: record the package hash/commit for a reproducible handoff, not just its version string.

A project deliberately selecting a native-only execution route can additionally declare requires_accelerators = ["hex_arithmetic", "material_body_pipeline", "q1_geometry"] under [project]. The check reports missing builds and loader errors before executing the case. These names reuse agentfem doctor's existing availability probes; no worker is started. The empty default preserves ordinary reference-only projects. Do not add this requirement to a project that supports reference fallback, and do not confuse availability with measured performance.

WSL execution environment

agentfem check and agentfem run issue read-only advisories for Windows-mounted working/output directories, low available memory, or numerical-library thread settings exceeding the CPU affinity. Run admission saves execution-environment.json beside the outputs. It records visible resources, mount detection and explicitly supplied thread settings, not a speed prediction or a claim that all available cores are used. The allowlisted mpi_environment records requested FI_PROVIDER and MPI asynchronous-progress settings when supplied. An absent variable is unknown, not an inferred default; a recorded request does not prove the active transport or actual CPU use. These operational observations are not checkpoint identity constraints. The snapshot never captures the entire process environment.

For I/O-heavy runs, a WSL-native working copy can avoid Windows filesystem interop costs. Export or back up results to Windows afterward: a distribution's internal files can be lost when it is unregistered. AgentFEM never moves the project, changes .wslconfig, or alters global thread settings automatically. Keep the existing project-custody safeguards. CPU affinity and startup memory are observations, not hardware-specific scientific limits; changing computers does not change the model's physical inputs.

See Microsoft's WSL filesystem guidance and WSL configuration reference. The advice does not replace measuring the actual installed backend: optional accelerators being available and being selected by the Step are different facts.