AgentFEM Architecture Review¶
This note records the current architecture direction from the perspective of traditional finite-element workflows and agent-oriented use.
For the durable FEniCSx-first architecture, AF-IR boundary, backend strategy,
agent repair protocol, and execution-evidence design, see
docs/air_architecture_roadmap.md. Public roadmaps communicate direction;
release gates, sequencing, risks, and competitive execution notes are kept in
the private engineering record.
Current Strengths¶
- The first-level modules mostly match standard FEM steps: studies, mesh import/read, models, spaces, fields, constraints, loads, forms, assembly, operators, problems, time integration, solvers, diagnostics, and output.
- Constitutive response relations are below
constitutive/, while material records and property containers are belowmaterials/. - Study assumptions now influence constitutive behavior where implemented, including 2D isotropic plane strain and plane stress elasticity.
- Weak boundary physics is below
boundary_models/, which separates Robin, impedance, absorbing, and convection-like terms from essential constraints and Neumann loads. - Application-specific geometry and source definitions are outside AgentFEM, keeping the core package reusable.
- External CAE mesh conversion is separated into
mesh/formats.py, keeping solver workflow code independent from Abaqus, NASTRAN, COMSOL, or VTK details. - The package has both human-facing workflow docs and skill-ready progressive references for agents.
- Study summaries, model summaries, mesh summaries, tag checks, material-property summaries, load summaries, constraint summaries, and boundary-model summaries now provide a first layer of agent-readable inspection.
- AF-IR 0.1 provides an explicitly experimental, versioned JSON-safe record of supported public model semantics.
- Structured validation issues now carry stable codes, object paths, severity, and repair hints.
- Operator compilation crosses a narrow backend adapter boundary while FEniCSx remains the only production backend.
Main Refinements Needed¶
-
Keep mesh import and mesh regions generic:
mesh/should own reusable Gmsh and XDMF import/read/write operations, named mesh regions, tag checks, summaries, and simple structured mesh constructors. Application packages still own problem-specific geometry construction and meshing parameters. External file conversion belongs inmesh/formats.py. -
Keep boundary concepts separate: Public strong boundary conditions should enter through
constraints/.constraints/boundary.pyis a low-level implementation helper for Dirichlet constants and dof application. Weak boundary physics belongs inboundary_models/. -
Keep study, model, and problem responsibilities separate:
studies.pydeclares context,models.pyregisters assets and checks the model, the_step_builders_*family modules construct built-in scientific procedures behind a thin_step_builders.pyfacade,step_providers.pyowns the public extension protocol and dispatch, the private registry owns deterministic selection, the built-in catalog owns AgentFEM predicates and lowerers, andproblems.pyrepresents discrete systems to solve.Model.stepremains the stable public entry point; adding a material family does not justify adding a case-specific method to every model. Historical builder methods remain thin 0.2.x compatibility delegates rather than parallel implementations. -
Make form construction more discoverable:
forms.pyshould expose small weak-form blocks with clear names, such as mass, stiffness, damping, body load, traction, and flux contributions. -
Keep time integration generic:
time/should contain method-level kernels and step-cadence helpers, while application solvers decide which fields, loads, and boundary models enter each step. -
Add examples only after APIs stabilize: Examples should demonstrate the workflow order without becoming hidden framework logic.
Current execution-contract decision¶
model.step(...) keeps separate, readable keywords for solver, output,
history, progress, and checkpoint choices. Internally they are normalized into
one immutable StepExecutionPolicy and retained by the Step execution
context. This is an inspection and provenance boundary, not a second user
configuration language.
The policy has three consequences:
- providers receive one consistent cross-cutting contract while retaining
their own scientific
StepOptionContract; solve_result()can consume construction-time output and transient-history requests without case-specific plumbing;- result metadata exposes the declared controls to humans, agents, GUIs, and provenance tools without serializing live PETSc or DOLFINx objects.
An omitted policy value means the selected provider owns the default. Result
metadata labels these values as declared_policies; the executable
metadata["step"] record remains authoritative for resolved numerical values.
0.3 boundary audit¶
The 0.3 audit treats file size as a maintenance signal, not as proof of a bad abstraction. A split is required when two modules own the same scientific decision or when a lower layer imports an orchestration layer.
Modelowns registration, inspection, and compatibility delegates. It does not own built-in solution construction. Transient heat lowering now follows the sameStepRequest -> provider -> _step_builders -> problemroute as the structural, nonlinear-material, and dynamics providers.- Model-facing validation and inspection retain their public methods but now delegate to private, side-effect-free owners. The validation owner may read provider capability declarations but cannot construct a problem; the inspection owner may serialize supported semantics but cannot solve or accept a result.
- Model-first operator verbs are selection facades, not form builders. Regional measure resolution, coefficient checks, lumped assembly, finite-strain/linear internal-force dispatch, and force-balance composition share the private operator lowering boundary.
- A release regression test requires every historical
*_step()method to remain a thin delegate and prevents providers from calling those compatibility methods. - Constant volumetric heat capacity is resolved once in
materials, rather than being reimplemented by the model facade and the thermal provider. - Core discovery now contains the ordinary engineering language. Procedure
and solver controls are advanced; raw
io, discreteproblems, and time kernels are expert. This changes presentation, not runtime availability. resultsowns scientific result semantics and the common completion path. Static, nonlinear, transient, and modal problems now delegate result assembly to private result factories; problem objects no longer duplicate field, history, artifact, checkpoint, or processing-metadata policy. Low-levelio.XDMFTimeSeriesremains an expert DOLFINx-compatible writer; ordinary workflows use the single-grid result writers andSimulationResult.- Constitutive modules own material-point laws, while
mechanicsbelongs to the procedure boundary and owns global finite-element integration of those laws. Generic checkpointing owns field/time state; cohesive checkpointing additionally owns physical interface identity. These are deliberate layer pairs, not duplicate implementations. _architecture_contract.pynow defines the seven stable ownership boundaries consumed by machine capability discovery. AST regression tests reject selected upward dependencies rather than relying on this prose.- Generic first- and second-order transient states moved from
problems.pytostate.py; the diagonal mass object moved tooperators. Compatibility aliases preserve existing imports while new code follows the correct owner. - State has one minimal structural contract for restart and atomic replacement. Procedure-specific trial creation remains explicit because a Newton increment and a fatigue cycle do not begin with the same scientific inputs.
- Exact MPC construction remains in
constraints, while compiled-form, PETSc-allocation, KSP and state-transfer lifecycle lives insolvers. The PDE benchmark consumes this shared boundary rather than owning a privatedolfinx_mpc.LinearProblem. Provider-specific reaction and work recovery is deliberately not moved into the solver. - Structural modal analysis now follows the same ownership rule:
mechanicsowns rigid-mode filtering and physical eigenpair selection,backendsowns distributed matrix reduction, SLEPc execution and deterministic teardown, andresultsowns modal fields and verification evidence.problems.modal_analysis(...)remains a compatibility construction route, not a second eigensolver implementation. - Reusable numerical allocations share the internal
PreparedSolvecontract: solve and summary while open, a visible terminalclosedstate, and an idempotentclose(). Execution scopes—not Model—own these resources, and summaries plus borrowed public fields remain readable after teardown.
The evidence-driven split is now complete at the first stable boundary:
_step_builders.py is a thin facade over five scientific-family modules;
provider protocol, deterministic selection, and the built-in catalog are
separate; nonlinear and transient evolution are no longer embedded in the
discrete-problem facade; result assembly is owned by results. Further splits
must demonstrate a new owner or dependency boundary rather than only a smaller
file. WSL2 remains a supported Windows route and an independently tracked
acceptance item; lack of local WSL2 evidence does not block 0.3 after Linux and
macOS installed-wheel acceptance passes.
0.4 foundation¶
The 0.4 line consolidates the middle layer before the public capability catalog grows again.
- Primitive operators no longer choose a concrete physical formulation; dispatch and model lowering own that decision.
- Built-in Step providers are discovered lazily, keeping the eager internal import graph acyclic.
- Execution events and reusable fracture evidence are backend-neutral records; compatibility imports remain available from their historical locations.
- J2 plasticity, creep, generalized-Maxwell, and provider-neutral small-strain materials share one internal Newton lifecycle for convergence, residual ownership, accepted line-search evaluations, and structured rejection. Constitutive updates and state commit/rollback remain formulation-owned.
- Finite-strain materials have one optional atomic batch contract. Existing scalar providers continue to work; vectorized native, compiled, and learned providers can update MPI-local integration points without Python point loops.
- CI maps focused source changes to stable owner suites. Complete serial/MPI and installed-wheel validation remains a release gate rather than a tax on every documentation or local implementation edit.
The detailed decision, non-goals, and release ladder are recorded in
knowledge/decisions/0037-freeze-the-04-foundation-before-broadening.md.
Agent-Oriented Refinements¶
- Every public helper should say what FEM concept it belongs to.
- Public function names should be explicit enough that an agent can choose them without reading implementation details first.
- Docs should prefer routing tables and decision rules over long prose.
- Error messages should explain modeling mistakes, such as mixing Dirichlet constraints with Neumann loads.
- Validation docs should name the smallest useful check for each layer: import check, form-shape check, assembly check, serial run, MPI run, and ParaView output check.
Suggested Priority¶
- Harden the current FEniCSx execution, result, visualization, campaign, and dataset path around selected real engineering analyses.
- Advance nonlinear materials through explicit maturity gates: material point, FEM integration, benchmark, then workflow.
- Verify external mesh volume/boundary set preservation with real format fixtures.
- Expand addressable validation for regions, assignments, operators, steps, solver policies, and result contracts.
- Evolve AF-IR identity/loading/migration only when an executable consumer or golden case requires it; do not let schema breadth outrun product evidence.