Scale transition
What the FE code needs
At each quadrature point a finite-element code solving a nonlinear problem needs two things from the material, per step:
the stress and the consistent tangent, together with the updated internal state
Where homogenization enters
The material response is a homogenization: the strain drives an RVE, the scheme returns its effective stiffness, and
All the nonlinearity sits in
is exact, not an approximation. No numerical differentiation is needed, and no algorithmic tangent has to be derived: the scheme already returns it.
This is what makes the coupling affordable
Because MaterialCache.
Several gradients, several fluxes
A poroelastic material takes a strain and a pore pressure, and returns a stress and a variation of fluid content:
The contract is therefore written with named gradients and fluxes, and the tangent as a set of blocks keyed flux then gradient:
| block | value | key |
|---|---|---|
:σε | ||
:σp | ||
:φε | ||
:φp |
A purely mechanical law declares only :σε and never sees the rest. This is the same shape MGIS uses for MFront's generic behaviors.
The one rule that bites
A Tensors.jl tensor — what Ferrite and every Julia FE code speaks — has no basis: its components are always global.
A TensND tensor returns its components in its own basis, and a homogenized stiffness whose RVE carries tilted crack families comes back in a rotated basis. Handing its raw array to an FE assembler rotates the material silently. Cross the boundary with to_tensors and from_tensors, never with get_array.
using MeanFieldHomogenization, TensND
C₀ = TensISO{3}(3 * 30.0, 2 * 18.0)
rve = RVE()
add_phase!(rve, :M, Ellipsoid(1.0), Dict(:C => C₀); fraction = :rest)
add_phase!(rve, :F, PennyCrack(1.0; euler_angles = (π / 4, 0.0)), Dict(:C => C₀);
density = 0.08)
C_hom = homogenize(rve, MoriTanaka())
raw = get_array(C_hom)[1, 1, 1, 1] # components in ITS OWN basis
global_ = to_tensors(C_hom)[1, 1, 1, 1] # components an FE code expects
(raw, global_)(52.054054054054056, 43.433607520564046)The two differ: the first is expressed in the crack frame, the second in the global one.