API — Poromechanics
MeanFieldHomogenization.Poromechanics Module
MeanFieldHomogenization.PoromechanicsPoroelastic upscaling: the Biot tensor
The sub-module is a post-processor, not a scheme. It takes a drained homogenized stiffness C_hom — from any cell and any scheme, or from elsewhere entirely — together with the solid stiffness C_s and the Lagrangian porosity φ, and closes the poroelastic constitutive law
using the classical poroelastic relations ([70]) in the form quoted as eq. (2) of [71]. No additional Eshelby problem is solved: everything follows from C_hom, C_s and φ.
Entry points
| Function | Returns |
|---|---|
biot_tensor | |
inverse_biot_modulus | |
biot_modulus | Inf for an incompressible solid) |
poroelastic_parameters | all three at once, inverting |
undrained_stiffness / drained_stiffness | |
skempton_tensor | |
terzaghi_stress / biot_effective_stress | the two effective-stress measures |
pore_volume_fraction |
Everything is plain TensND algebra, hence type-generic (Float64, BigFloat, ForwardDiff.Dual, ComplexF64, SymPy.Sym) at no cost.
Homogeneous solid phase
The relations above hold when the solid phase has uniform elastic properties — the case of a rock matrix with pores or fractures. A medium built from two distinct solid constituents needs the general Levin/eigenstrain route, and C_s is then not defined.
Biot parameters
MeanFieldHomogenization.Poromechanics.biot_tensor Function
biot_tensor(C_hom, C_s) -> Tens{2,3}Biot tensor C_s, from its drained homogenized stiffness C_hom:
\boldsymbol{B} is the tensor appearing in the poroelastic law
Two limits are worth remembering as sanity checks: a homogeneous medium (C_hom == C_s) gives
Homogeneous solid phase only
These relations rest on the solid phase having uniform elastic properties. A medium with two distinct solid constituents needs the full Levin/eigenstrain route instead, and C_s is then not defined.
Pass the solid stiffness, not its compliance — the inverse is taken internally. Computing several poroelastic parameters at once is cheaper through poroelastic_parameters, which inverts C_s only once.
See also inverse_biot_modulus, undrained_stiffness, terzaghi_stress.
biot_tensor(rve::RVE, C_hom; solid = nothing, property = :C) -> Tens{2,3}biot_tensor with the skeleton stiffness read from the phase that plays the homogeneous solid of microporomechanics.
solid names that phase. Left unset it is the one taking up the volume complement, which is the usual reading of a porous RVE; an RVE that designates none has to be told, because no container can know which of its phases is the skeleton.
MeanFieldHomogenization.Poromechanics.inverse_biot_modulus Function
inverse_biot_modulus(C_s, B, φ) -> NumberInverse Biot modulus
φ is the Lagrangian porosity of the connected pore space in the reference configuration — the volume fraction actually occupied by the fluid, which for a fractured medium is the crack volume fraction pore_volume_fraction).
For an isotropic medium this reduces to the textbook
Incompressible saturating fluid
This expression assumes the pore fluid is incompressible, which is the setting of [71]. A fluid of finite bulk modulus
Add it yourself if the fluid compressibility matters — the function does not, since it has no way of knowing k_f. The distinction is not cosmetic: with an incompressible fluid and a compressible solid the fluid is effectively stiffer than the grains, and the Skempton coefficient then exceeds one (see skempton_tensor).
The inverse is the primitive rather than biot_modulus returns Inf in that case, which is correct but not something to feed to a linear solver.
See also biot_tensor, biot_modulus, poroelastic_parameters.
MeanFieldHomogenization.Poromechanics.biot_modulus Function
biot_modulus(C_s, B, φ) -> NumberBiot modulus inverse_biot_modulus.
Returns Inf for an incompressible solid phase (inverse_biot_modulus wherever the value is assembled into a system matrix.
MeanFieldHomogenization.Poromechanics.poroelastic_parameters Function
poroelastic_parameters(C_hom, C_s, φ) -> NamedTupleEvery poroelastic parameter of a saturated medium with a homogeneous solid phase, in one pass:
(; B, inverse_modulus, modulus)with B the biot_tensor, inverse_modulus the inverse_biot_modulus modulus its reciprocal
C_s is inverted once, which is why this is the entry point the Gauss-point materials use rather than the three functions separately.
julia> using MeanFieldHomogenization, TensND
julia> C_s = TensISO{3}(3 * 20.0, 2 * 12.0); # k_s = 20, μ_s = 12
julia> rve = RVE();
julia> add_phase!(rve, :M, Ellipsoid(1.0), Dict(:C => C_s); fraction = :rest);
julia> add_phase!(rve, :P, Ellipsoid(1.0), Dict(:C => TensISO{3}(1.0e-9, 1.0e-9));
fraction = 0.2);
julia> par = poroelastic_parameters(homogenize(rve, MoriTanaka()), C_s, 0.2);
julia> round(par.B[1, 1], digits = 4) # b = 1 - k_MT/k_s = 1 - 12.8/20
0.36poroelastic_parameters(rve::RVE, C_hom, φ; solid = nothing, property = :C) -> NamedTupleporoelastic_parameters with the skeleton stiffness read from the phase that plays the homogeneous solid — see biot_tensor for solid.
Drained ↔ undrained
MeanFieldHomogenization.Poromechanics.undrained_stiffness Function
undrained_stiffness(C_hom, B, M) -> Tens{4,3}Undrained stiffness
It is the tangent stiffness of the closed system, obtained by eliminating p from the poroelastic law under the undrained condition M = Inf (incompressible solid and fluid) makes the result infinite, which is the correct statement that no volume change is possible.
See also drained_stiffness, skempton_tensor.
MeanFieldHomogenization.Poromechanics.drained_stiffness Function
drained_stiffness(C_u, B, M) -> Tens{4,3}Inverse of undrained_stiffness: recover the drained stiffness
MeanFieldHomogenization.Poromechanics.skempton_tensor Function
skempton_tensor(C_hom, B, M) -> Tens{2,3}Skempton tensor
Under isotropic compression
The bound B ≤ 1 does not hold here
The familiar inverse_biot_modulus assumes an incompressible fluid (
Effective stresses and porosity
MeanFieldHomogenization.Poromechanics.terzaghi_stress Function
terzaghi_stress(Σ, p) -> Tens{2,3}Terzaghi effective stress
This is the loading measure that drives the microstructure: for a porous or fractured medium whose solid phase has uniform elastic properties, the problem defined by
a dry problem (no fluid pressure) under the macroscopic stress
, during which pores and fractures may open or close, anda superimposed loading
whose solution is the uniform pair , .
Step 2 carries no strain singularity, so it cannot change the aperture of a flat crack. All the information about the evolution of the pore space is therefore contained in step 1, i.e. it depends on the Terzaghi effective stress alone. This is the argument of [71] § 1.1 and the reason why the constitutive laws of MeanFieldHomogenization.Constitutive drive their internal state with terzaghi_stress rather than with \boldsymbol{\Sigma}.
Do not confuse it with biot_effective_stress, which is the measure that makes the macroscopic constitutive law take its drained form.
See also biot_tensor.
MeanFieldHomogenization.Poromechanics.biot_effective_stress Function
biot_effective_stress(Σ, p, B) -> Tens{2,3}Biot effective stress
It coincides with terzaghi_stress only when
See also biot_tensor, terzaghi_stress.
MeanFieldHomogenization.Poromechanics.pore_volume_fraction Function
pore_volume_fraction(rve::RVE, names) -> NumberSum of the volume fractions of the phases listed in names — the Lagrangian porosity of the connected pore space, for use as the φ argument of inverse_biot_modulus and poroelastic_parameters.
names is any iterable of phase symbols; a single Symbol is accepted too. Passing the pore phases explicitly is deliberate: an RVE has no way of knowing which of its soft inclusions are fluid-filled and connected, and guessing would silently produce a wrong Biot modulus.
Crack phases carry no volume
A CrackDensity phase contributes zero here, because a flat crack has no volume: its fraction MeanFieldHomogenization.Constitutive does — and passed to poroelastic_parameters directly.