Plasticity and material models
Materials
Barcelona Basic Model
Elastoplasticity for unsaturated soils, in which suction is a second loading variable: drying expands the yield surface, wetting shrinks it, and a soil wetted under constant stress can therefore be pushed to yield and collapse.
PoroMechanics.BBM Type
BBM(; κ, λ0, r, β, M, k_s, nu, e0, p_ref, p_min)| Field | Meaning |
|---|---|
κ | elastic swelling index [-] |
λ0 | virgin compression index at zero suction [-] |
r | ratio |
β | rate at which the LC curve saturates [Pa⁻¹] |
M | slope of the critical state line [-] |
k_s | cohesion–suction coefficient [-] |
nu | Poisson's ratio [-] |
e0 | initial void ratio [-] |
p_ref | reference pressure of the LC law [Pa] |
p_min | floor on the mean compressive stress [Pa] |
Defaults are the parameter set of the reference test case.
sourcePoroMechanics.BBMState Type
BBMState(σ, ε, pc_star, εv_p, suction)Internal variables: the stress and strain carried from the previous step (the elastic law is pressure dependent), the preconsolidation pressure at zero suction pc_star — the hardening variable — the accumulated volumetric plastic strain, and the suction the point currently sits at.
PoroMechanics.compression_index Function
compression_index(m, s) -> λ(s)PoroMechanics.preconsolidation Function
preconsolidation(m, s, pc_star) -> p₀(s)The Loading–Collapse curve, which is the model's central idea:
PoroMechanics.yield_function Function
yield_function(m, p, q, s, pc_star) -> fAn ellipse in the
yield_function(m::DruckerPrager, σ) -> fPoroMechanics.bbm_moduli Function
bbm_moduli(m, p) -> (K, G)p floored at m.p_min because a vanishing modulus would break the solve and a soil in real tension is outside this law.
PoroMechanics.suction_stress_increment Function
suction_stress_increment(m, p, s, s_n) -> Δσ_mThe elastic mean-stress change caused by a change of suction at constant strain,
the second half of the BBM's elastic law: volumetric strain responds to suction as well as to stress, ``d\varepsilon_v^e = \frac{\kappa}{1+e_0}\frac{d\bar p}{\bar p}
- \frac{\kappa_s}{1+e_0}\frac{ds}{s + p_{atm}}``.
The atmospheric offset is what keeps the logarithm finite at zero suction, where a saturated soil must still have a defined stiffness. Drying raises s, so at constant net stress the sample shrinks — the reversible half of the shrinkage, the irreversible half being what the LC curve produces.
PoroMechanics.log_mean Function
log_mean(a, b)The logarithmic mean
It is the exact average of a quantity that varies exponentially between a and b, which is what a pressure obeying
PoroMechanics.step_shear_modulus Function
step_shear_modulus(m, p_n, p_tr, scheme) -> GThe shear modulus to use across a step, from the pressures at its two ends.
Under Val(:exact) it is evaluated at the logarithmic mean pressure, which integrates G at the incoming state. Under Val(:explicit) it is frozen at p_n, which is what Bil does.
A constant G_const short-circuits both.
PoroMechanics.trial_stress Function
trial_stress(m, ε, s, state, scheme)The elastic predictor: the stress the material would carry at strain ε and suction s if the step were entirely elastic.
Under Val(:exact) the volumetric part is integrated in closed form. The BBM's elastic law is
which separates and integrates to
with no step-size error at all. Expanding the exponential to first order recovers
Under Val(:explicit) the incremental form is used instead, to reproduce Bil.
PoroMechanics.hardening_modulus Function
hardening_modulus(m) -> (1+e₀)/(λ(0) − κ)The coefficient of the hardening law
PoroMechanics.deviatoric_tolerance Function
deviatoric_tolerance(m, p_tr) -> q_tolBelow what deviatoric stress a state counts as hydrostatic.
This is not defensive padding: at e — whatever that direction happens to be. Under isotropic loading e is pure round-off, so the expression yields a full-magnitude tensor with a random orientation, and it poisons the tangent rather than vanishing from it.
The tolerance is relative to the stress the material actually carries, because an absolute one would be meaningless across the range of pressures a soil sees.
sourcePoroMechanics.return_residual Function
return_residual(m, x, p_tr, q_tr, s, pc_star_n, K, G) -> (r1, r2)Residual of the return map, in the two unknowns x = (p, Δγ).
Given
The hardening is integrated exponentially,
PoroMechanics.solve_return_map Function
solve_return_map(m, p_tr, q_tr, s, pc_star_n, p_n, scheme; tol, maxiter)Newton on the two-equation residual, with the Jacobian from ForwardDiff. Returns (p, Δγ, q, pc_star, converged).
PoroMechanics.elastoplastic_tangent Function
elastoplastic_tangent(m, C_e, p, q, s, pc_star, Δγ, K, G, dev_tr, q_tr, ::Val{dim})The continuum elastoplastic tangent, from the consistency condition differentiated at the converged point:
with NaN.
What this is not. The algorithmic (consistent) tangent, which is the exact Jacobian of the discrete return map, differs from this one by terms of order algorithmic_tangent is what material_response actually returns; this one is kept because the comparison between the two is the measurement that justifies it.
PoroMechanics.algorithmic_tangent Function
algorithmic_tangent(m, C_e, p, Δγ, p_tr, q_tr, s, pc_star_n, K, G, dev_tr, ::Val{dim})The algorithmic tangent: the exact Jacobian elastoplastic_tangent.
The returned stress is a function of the trial state through the converged unknowns,
and
so the tangent costs two extra back-substitutions, not a second solve. Chaining with
This is what makes a global Newton converge quadratically. It is also where Julia earns its place on this model: ForwardDiff supplies
PoroMechanics.ContinuumTangent Type
ContinuumTangent(model)A material that answers exactly like model but returns the continuum tangent instead of the algorithmic one.
It exists to be measured against, not to be used: it is how the claim that the algorithmic tangent is worth its derivation gets tested rather than asserted. Wrapping rather than adding a flag to BBM keeps the choice out of the model, where it does not belong — a constitutive law should not carry a switch that changes only how fast the solver reaches the answer it would have given anyway.
PoroMechanics.ExplicitPredictor Type
ExplicitPredictor(model)A material that answers like model but integrates the elastic law incrementally, freezing the moduli at the incoming state, instead of in closed form.
That is the scheme Bil uses, and it is first-order accurate in the step: over a path that loads and unloads several times the error accumulates to the per-cent level. This wrapper exists so that the comparison against Bil can be made on Bil's own terms, and so that the improvement from integrating exactly is measured rather than asserted. It is not the recommended way to run the model.
sourceDrucker-Prager
Perfect plasticity with a non-associated flow rule: friction sets the yield cone, dilatancy sets the plastic flow direction, and keeping the two apart is what lets the model shear without inventing volume.
PoroMechanics.DruckerPrager Type
DruckerPrager(; E, nu, cohesion, friction, dilatancy)Perfect Drucker-Prager plasticity on isotropic linear elasticity.
| field | meaning |
|---|---|
elastic | the elastic law, a LinearElastic |
cohesion | |
friction | |
dilatancy |
Angles are stored in radians. Deck files usually quote degrees — convert at the call site rather than inside the model, so the units of a stored parameter are never in doubt.
Every coefficient is type-parameterized, so a ForwardDiff.Dual can enter the cohesion or the friction angle and a result can be differentiated with respect to them.
PoroMechanics.DruckerPragerState Type
DruckerPragerState(σ, ε, εp, γp)Stress, total strain, plastic strain and the cumulative plastic shear strain
γp is carried even though perfect plasticity does not use it: it is the measure a softening or hardening cohesion is a function of, and a state that cannot report how much plastic straining it has been through is useless for anything but the perfect case.
Each tensor carries its own type parameter. That is not pedantry: differentiating with respect to a material parameter — the cohesion, say — makes the stress and the plastic strain Dual while the imposed strain stays Float64, and a state that demanded one shared type would reject exactly the case this package exists to support.
PoroMechanics.drucker_prager_return Function
drucker_prager_return(m, ε, εp_n, σ0 = zero(ε)) -> (σ, εp, Δγ, at_apex)The elastic predictor and its plastic corrector, as a pure function of the strain.
σ0 is a prestress: the stress the material already carries at zero strain. Geotechnical cases are posed this way — base/Poroplast starts at −11.5 MPa isotropic with the mesh undeformed — and folding it into the predictor is the only place it belongs, because the yield check has to see the total stress and not the increment.
Perfect plasticity with a linear elastic predictor makes the smooth return closed-form: consistency on
so the returned state follows in one step. No inner Newton is needed, which is the whole difference in cost between this and BBM.
Two returns exist and both are needed. The smooth one slides the trial stress back onto the side of the cone; it is valid only while the corrected
PoroMechanics.friction_coefficient Function
friction_coefficient(m::DruckerPrager) -> f_fPoroMechanics.cohesion_intercept Function
cohesion_intercept(m::DruckerPrager) -> c_cPoroMechanics.dilatancy_coefficient Function
dilatancy_coefficient(m::DruckerPrager) -> d_dfriction_coefficient exactly when the rule is associated.
PoroMechanics.apex_pressure Function
apex_pressure(m::DruckerPrager) -> p_apexThe mean stress at which the cone closes, material_response.
Infinite for a frictionless material, which is the von Mises limit and has no apex.
sourceA Biot medium with an arbitrary skeleton
PoroMechanics.BiotPlastic Type
BiotPlastic(; skeleton, b, beta, N, k, mu_l)A Biot medium whose skeleton is an arbitrary elastoplastic material.
BiotPoroelastic hard-wires a LinearElastic skeleton, which is what makes poro_response short and what stops it short of base/Poroplast: that case is a Drucker-Prager skeleton under a Biot coupling, and no shipped date of it is elastic. This struct is the same hinge with the skeleton left open.
| field | meaning |
|---|---|
skeleton | the drained stress–strain law — any AbstractMaterial |
b | Biot coefficient of the stress coupling and of the elastic porosity change [-] |
beta | coefficient with which the plastic volume change enters the porosity [-] |
N | storage modulus at constant strain [Pa⁻¹] |
k | intrinsic permeability [m²] |
mu_l | dynamic viscosity [Pa·s] |
b and beta are separate because Bil's Poroplast keeps them separate: its porosity is
so a plastic volume change opens pore space at a different rate than an elastic one. They coincide in base/Poroplast, where both are 0.8, and a comparison that assumed they always do would pass there and be wrong everywhere else.
PoroMechanics.porosity Function
porosity(m::BiotPlastic, phi0, ε, εp, p, p0) -> φLagrangian porosity, following Bil's Poroplast:
Splitting the volumetric strain into its elastic and plastic parts, each with its own coefficient, is what b and beta are for. With beta == b this collapses to the usual
porosity(m::FickModel, region) -> φPorosity of cell region region. Dispatch rather than a run-time branch, so a single-region model pays nothing for the generality.