From derivatives to a strength criterion
Before this page
The tutorials Every scheme on the whole porosity range, for the schemes compared below, and Derivatives and sensitivities, for the derivatives from which the criterion is assembled.
This capstone tutorial combines the last three pages — porous materials, scheme comparison, and automatic differentiation — into a single applied result: a macroscopic strength criterion for a porous solid, derived without ever writing a closed-form strength formula by hand. It ports the porous strength-criterion benchmark of the Echoes book (Barthélémy, 2026).
Setup
The solid and pore are both oblate spheroids (aspect ratio IsoSymmetrize, as in the porous benchmark tutorial), so the homogenized stiffness is isotropic. The solid is much stiffer than the pore, at a fixed porosity
using MeanFieldHomogenization
using TensND
using ForwardDiff
using LinearAlgebra
using Plots
gr() # headless backend; GKSwstype is set to "100" in make.jl
const k_s, μ_s0 = 1.0e6, 1.0
const TINY = 1.0e-12
const ω = 0.1
const φ = 0.15The criterion
The solid obeys a von Mises criterion written on the norm of its stress deviator,
For spherical pores in an incompressible solid, Mori–Tanaka gives
(k_hom, μ_hom) gives both at once:
function k_mu_hom(μ_s::T, scheme) where {T}
r = RVE(; T = T, distribution_shape = Ellipsoid(1.0))
add_phase!(r, :SOLID, Spheroid(ω), Dict(:C => iso_stiffness(convert(T, k_s), μ_s)); fraction = :rest, symmetrize = IsoSymmetrize())
add_phase!(r, :PORE, Spheroid(ω), Dict(:C => iso_stiffness(convert(T, TINY), convert(T, TINY)));
fraction = convert(T, φ), symmetrize = IsoSymmetrize())
C = homogenize(r, scheme, :C)
return [k_mu(best_fit_iso(C))...]
end
function ellipse_radii(scheme)
k_hom, μ_hom = k_mu_hom(μ_s0, scheme)
dk_dμs, dμ_dμs = ForwardDiff.derivative(μ_s -> k_mu_hom(μ_s, scheme), μ_s0)
A = (μ_s0 / k_hom)^2 * dk_dμs
B = (μ_s0 / μ_hom)^2 * dμ_dμs
a = sqrt((1 - φ) / (2A)) # semi-axis along Σ_m/σ_o
b = sqrt((1 - φ) / B) # semi-axis along Σ_d/σ_o
return a, b
endk_mu_hom uses only public accessors — iso_stiffness, homogenize, best_fit_iso, k_mu — the same building blocks as every earlier tutorial; there is no need to reach into the package's internals to differentiate through a homogenization call, whatever scheme is used.
Strength ellipses for six schemes
SCHEMES = [
(MoriTanaka(), "MT"),
(DiluteDual(), "DiluteDual"),
(SelfConsistent(; abstol = 1.0e-8, maxiters = 300, select_best = true), "SelfConsistent"),
(AsymmetricSelfConsistent(; abstol = 1.0e-8, maxiters = 300, select_best = true), "AsymmetricSelfConsistent"),
(PonteCastanedaWillis(), "PCW"),
(Maxwell(), "Maxwell"),
]
θ = range(0, π; length = 100)
plt = plot(;
xlabel = "Σ_m / σ_o", ylabel = "Σ_d / σ_o",
aspect_ratio = :equal, legend = :outerright, framestyle = :box, size = (760, 480),
)
for (scheme, label) in SCHEMES
a, b = ellipse_radii(scheme)
plot!(plt, a .* cos.(θ), b .* sin.(θ); lw = 2, label = label)
end
hline!(plt, [0.0]; color = :black, lw = 0.5, label = "")
vline!(plt, [0.0]; color = :black, lw = 0.5, label = "")
plt
The ellipses differ noticeably between schemes — SelfConsistent and AsymmetricSelfConsistent predict a markedly smaller admissible domain than Mori-Tanaka or Maxwell at this porosity, the same qualitative ranking (percolating vs. isolated-pore topology) seen throughout the porous benchmark tutorial. Mean-field homogenization gives the moduli; automatic differentiation gives their sensitivities; together they yield a macroscopic strength criterion — with no closed-form derivative ever written by hand, and no assumption beyond the choice of scheme. For the same construction at three nested scales, see Quasi-brittle strength of cement paste and mortar.
Where to go next
Nonlinear solvers for the self-consistent fixed point revisits the criterion with an external solver for the self-consistent scheme and checks that the ellipse does not depend on it. The same construction at three nested scales is carried out in Quasi-brittle strength of cement paste and mortar.