Heat transfer¶
AgentFEM supports steady conduction and implicit transient heat transfer through the same study/model/step/result lifecycle used by solid mechanics.
Current routes¶
- steady heat transfer with conductivity and thermal boundary conditions;
- implicit Euler transient heat transfer with structured increments;
- conservative nonlinear implicit heat transfer with tabulated (k(T)) and (c_p(T)), automatic residual linearization, and atomic failed-step rollback;
- accepted-time temperature-field capture with explicit interpolation, out-of-range policy, partition-portable persistence, and content identity;
- thermal-field handoff to thermoelastic stress workflows;
- common result, progress, checkpoint, and verification concepts.
Steady and constant-property implicit transient conduction on a rectangular periodic cell accept
constraints.rectangular_periodic_mpc(temperature) through the ordinary
model.step(...) call. It uses the same exact-MPC lowering as linear solids,
including serial/MPI diagnostics and pre-assembly rejection of overlapping or
ambiguous constraint providers. The constant operator lifecycle is prepared
once per transient run and reused while the history/source vector changes.
The same provider-owned dual recovery is available after a converged linear
solve; in a thermal problem the nodal distribution is the algebraic flux dual
to the homogeneous periodic temperature relation rather than a mechanical
force. Structural force/work quantities are therefore attached only by solid
analysis Steps.
General master/slave geometry still requires a dedicated reviewed construction
provider.
Typical workflow¶
thermal study → mesh/regions → temperature field → conductivity/capacity
→ temperature/flux/convection conditions → transient or steady step
→ temperature/flux histories → verification → optional stress handoff
Temperature history handoff¶
The transient step can retain the solved field as a physical-time object:
step = thermal_model.step(target=temperature, dt=10.0, steps=100)
temperature_history = step.capture_history(
name="temperature",
unit="K",
interpolation="linear",
)
step.solve_result(output="temperature.xdmf")
creep_step = mechanical_model.step(
target=displacement,
material=creep_material,
duration=1000.0,
temperature=temperature_history,
)
temperature_history is not an output-frame index. It is sampled using the
physical time requested by the receiving step. Creep cutback therefore
restores both material state and temperature to the attempted increment's
starting time. The default rejects requests beyond the recorded interval;
endpoint holding requires outside="clamp" explicitly.
Saved nodal histories use coordinate-keyed physical DOF identities rather than MPI-local array numbering. The same archive can therefore be written with one partition count and restored with another, provided the mesh and function space are scientifically identical. The first format is deliberately root-gathered and compact; it is a reproducible transfer/checkpoint artifact, not yet an extreme-scale parallel field database.
Temperature-dependent sequential material data use inspectable property tables rather than anonymous interpolation functions:
young = materials.temperature_property(
[300.0, 500.0, 700.0],
[210e9, 190e9, 160e9],
name="young",
unit="Pa",
extrapolation="constant",
)
material = constitutive.temperature_dependent_thermoelastic(
young=young,
poisson=0.3,
density=7800.0,
thermal_expansion=12e-6,
conductivity=45.0,
specific_heat=500.0,
)
K = mechanical_model.stiffness(displacement, temperature=temperature)
The explicit constant extrapolation is required for a bounded UFL
coefficient; scalar evaluation defaults to an error outside the supplied
temperature range.
When conductivity or specific heat is a TemperaturePropertyTable, the same
top-level call automatically uses
Using the enthalpy difference rather than
\(\rho c_p(T_{n+1})(T_{n+1}-T_n)\) keeps the discrete heat content consistent
with the property table. Nonlinear convergence evidence, heat-balance history,
checkpoint/restart, output, and MPI execution remain attached to the ordinary
transient Step. A failed nonlinear increment restores both current and accepted
temperature fields. Explicit C= or K= overrides are rejected on this route
because they would mix two incompatible descriptions of the same physics.
The next depth is heat generated by inelastic dissipation, a larger external power-component thermal-to-creep benchmark, adaptive nonlinear thermal increments, and monolithic coupling where two-way feedback is physically necessary.
Sequential thermoelasticity and eigenstrain¶
Temperature does not become stress because of a field name. Declare the stress-free strain source explicitly, then let the ordinary static-solid Step lower it over the registered material regions:
from agentfem import eigenstrains
model.eigenstrain(eigenstrains.thermal(temperature))
result = model.step(target=displacement).solve_result()
For several materials, every material owns a disjoint CellRegion and the
regions cover the mesh exactly once. AgentFEM assembles regional stiffness and
thermal virtual work without user-written UFL measure concatenation.
The scientific result contains one physical stress S and the strain
decomposition E_TOTAL, E_EIGEN, E_MECH. E remains the compatibility
spelling of total infinitesimal strain. These are discontinuous projections
and are not averaged across material interfaces.
When the model declares a consistent unit system, the result manifest records displacement, stress/energy-density, temperature and dimensionless-strain units explicitly. AgentFEM never infers a unit system from coefficient magnitudes.