Skip to content

Engineering Loads, Steps, and Resultants

AgentFEM treats common CAE operations as reusable scientific assets rather than case-local UFL fragments.

Inspectable scientific formulas

Configuration files and AI agents often need to describe a source, boundary value, or initial field as mathematics rather than executable Python:

source = expressions.as_ufl(
    "2*pi**2*sin(pi*x)*sin(pi*y)",
    domain,
)
expressions.interpolate(
    temperature,
    "exp(-t)*sin(pi*x)*sin(pi*y)",
    parameters={"t": 0.25},
)

ScientificExpression is a deliberately small language. It accepts x/y/z/t, declared parameters, arithmetic, and reviewed functions such as sin, cos, exp, and sqrt. Arbitrary calls, attributes, indexing, and Python statements are rejected before UFL compilation. Its summary retains the original formula and language version, so an agent-readable input remains inspectable instead of becoming an opaque callable.

The same validated formula has two deliberate execution routes. as_ufl lowers symbolic physics into a variational form; interpolate evaluates known loads, coefficients, initial values, and boundary data directly on NumPy coordinate arrays without eval or a per-form C++ JIT. This keeps scientific meaning identical while allowing many generated cases to reuse one compiled finite-element operator.

This interface is for trusted mathematical structure, not for guessing a missing equation. A formula that is inconsistent with its stated PDE remains a model or dataset error.

Continuum loads

model.elastic_foundation(on=base, stiffness=2.0e8, mode="normal")
model.centrifugal((0.0, 0.0, 120.0), center=(0.0, 0.0, 0.0))
model.hydrostatic_pressure(
    density=1000.0, gravity=(0.0, 0.0, -9.81),
    reference_point=(0.0, 0.0, 0.0), on=wetted_surface,
)
model.distributing_coupling(
    (0.0, 0.0, -50_000.0), moment=(2_000.0, 0.0, 0.0),
    reference_point=load_application_point, on=loaded_surface,
)

For ordinary self-weight, density belongs to the material and acceleration belongs to the load:

steel = model.material(
    elasticity.isotropic_elastic(
        young=210.0e9,
        poisson=0.30,
        density=7850.0,
    )
)
model.gravity((0.0, 0.0, -9.81))

model.gravity(...) creates the reference volume force density rho * acceleration. With multiple registered materials it creates one load per explicitly assigned material region, preserving each density. A raw force density remains available as model.body_force(...). Both routes enter the same external-force operator, amplitude, Step activation, reaction, and work contracts used by the selected procedure. Abaqus *DLOAD, GRAV migration can lower one or more explicitly assigned three-dimensional solid-section regions; parent or overlapping ELSET membership is never guessed.

The foundation contributes a boundary stiffness matrix. Centrifugal loading uses registered material densities and regions. Hydrostatic pressure follows p = p_ref + rho g dot (x - x_ref). Distributing coupling constructs a traction whose integrated force and moment equal the reference-point resultants, avoiding a mesh-sensitive single solid-node force.

Local coordinates and named reference points

local = coordinates.cartesian(
    origin=(0.0, 0.0, 0.0),
    x=(0.0, 1.0, 0.0), y=(-1.0, 0.0, 0.0), z=(0.0, 0.0, 1.0),
    name="fixture",
)
rp = coordinates.reference_point((100.0, 20.0, 0.0), name="RP-1")

model.remote_force(
    (0.0, -50_000.0, 0.0), moment=(2_000.0, 0.0, 0.0),
    reference_point=rp, system=local, on=loaded_surface,
)
model.remote_displacement(
    U, reference_point=rp, translation=(0.0, 1.0, 0.0),
    rotation=(0.0, 0.0, 0.01), system=local, on=driven_surface,
)

Coordinate axes are validated as a right-handed orthonormal basis. Vector and tensor transforms are public and inspectable. remote_force uses the existing continuum distribution and preserves force and moment about the named point; remote_displacement prescribes the corresponding rigid boundary motion and participates in nonlinear load-factor ramping. It does not claim an unknown reference-point degree of freedom or a general kinematic MPC.

Step inheritance

preload = model.stage("preload")
preload.activate_load(gravity)

service = model.stage("service", previous=preload)
service.activate_load(pressure)
service.deactivate_load("temporary_fixture_force")
service.deactivate_constraint("temporary_fixture")
service.predefine(temperature, initial_temperature)

step = model.step(target=U, configuration=service)

An EngineeringStep says which named loads and constraints are active. It is separate from steps.automatic(...), which controls increments, and from solvers.newton(...), which controls algebraic convergence. Only explicit changes are recorded; other assets inherit from the preceding Step.

Lowering uses a shallow configured Model view. The source Model's load and constraint registries are never temporarily replaced, while the executable Step retains the exact active view used to produce its result. This makes exception handling, concurrent campaign preparation, and provenance inspection deterministic. Applying an explicitly declared predefined field remains an intentional field-state operation.

Engineering resultants

section = results.section_resultant(S, on=cut, about=reference_point)
free_body = results.free_body_resultant(
    boundary_tractions=((traction, outer_boundary),),
    body_forces=((rho_g, volume),), about=reference_point,
)
path = results.sample_path(S, start=a, end=b)

Section force/moment, free-body force/moment, and path sampling are MPI-global scientific quantities for verification, histories, campaigns, and learning datasets. A fully kinematic reference-point MPC remains separate from the implemented load-distribution contract.

Repeated linear systems

For a transient or parameter loop whose left-hand side and constrained degree set stay fixed, prepare the algebraic problem once:

with solvers.prepare_linear_problem(a, L, T, bcs=bcs, options=options) as solve:
    for time_value in accepted_times:
        t.value = time_value
        solve.solve()  # refreshes the right-hand side; reuses A and the KSP

This is the lower-level counterpart of AgentFEM's managed transient Steps. It keeps the mathematical forms public while avoiding repeated matrix assembly and factorization in external protocol adapters.