Skip to content

Composed friction partition - #1764

Open
IvarStefansson wants to merge 7 commits into
damage-dissipation-scalefrom
composed-friction-partition
Open

Composed friction partition#1764
IvarStefansson wants to merge 7 commits into
damage-dissipation-scalefrom
composed-friction-partition

Conversation

@IvarStefansson

@IvarStefansson IvarStefansson commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Stacked on #1762the base branch is damage-dissipation-scale, not develop.

Introduces the fracture friction law of Stefansson et al. (in preparation): friction on
surfaces inclined by the dilation angle, a stress-dependent split between climbing over
asperities and shearing through them, and the wear of both. The damage driver is
unchanged in this PR, so the history variable keeps the meaning it has on #1762.

Three constitutive layers

FractureDamage             × d^α on tangent_dilation_angle,
  (wear)                     ploughing_friction_coefficient, reference_fracture_gap
AsperityStressPartition    a_s: (1−a_s) × tangent;  friction_coefficient = super() + a_s·μ_p0
  (stress)                   stress_partition, transitional_normal_traction, …
DilationRotatedFriction    friction_coefficient = (μ_b + tanψ)/(1 − μ_b·tanψ)
  (kinematics)               basic_friction_coefficient, pole guard
ShearDilation              tangent_dilation_angle = tan ψ₀
CoulombFrictionBound       friction_bound = −μ·t_n

Each layer modifies the one below through super(), and each is usable without the ones
above it. DilationRotatedFriction introduces no new material constantsμ_b and
ψ₀ are the friction_coefficient and dilation_angle already in SolidConstants — so
any model with ShearDilation can take Patton's tan(φ_b + ψ) on its own. Verified on a
plain MomentumBalance with plain SolidConstants: 0.776777313376 against
tan(arctan(0.6) + 0.12) = 0.776777313376.

FrictionDamage and DilationDamage merge into one FractureDamage: the composed
coefficient contains both damage states, so neither channel can be mixed in alone any
more. A channel is switched off by d₀^α = 1 rather than by omitting a mixin, and the
two identical softening bodies are now one private helper.

New constants live in AsperityContactSolidConstants, which FractureDamageSolidConstants
inherits from, so a model wanting σ_T need not instantiate a damage constants class.
transitional_normal_traction defaults to infinity, holding a_s ≡ 0 and leaving the
partition inert; the 1.0 its neighbours use would pin a_s = 1 — silent full ploughing
under any real traction.

A behavioural change worth flagging

The friction floor moves. Previously the damage state multiplied the whole coefficient,
so it decayed to d₀^f·μ_b; now it multiplies only the ploughing term, and the floor is
μ_b itself — the rock surfaces' own friction, which no amount of asperity wear removes.
d₀^f = 0 becomes admissible, and is the physical statement: asperities worn flat cease
to plough.

In the dilation_angle = 0 fixture used by the integration tests this raises μ from
0.006789 to 0.010000. Downstream parameterisations that relied on d₀^f to set the
friction floor need revisiting.

Commits

ENH: Tangent of the dilation angle as a constitutive method results-neutral extraction from ShearDilation
ENH: Stress partition of asperity contact a_s = 1 − clip(1 − σ_n/σ_T, 0, 1)^K
API: Widen the damage constant accessors to Operator see note below
MAINT: Merge the dilation and friction damage constitutive mixins results-neutral
MAINT: Remove the spurious mated gap from the damage example prerequisite, see note below
ENH: Composed friction coefficient and damaged mated gap the law, plus its tests
TST: Retune the fourth-step damage length tolerance consequence of the floor moving

Verification

Three of the six substantive commits are results-neutral and were gated on the twelve
pinned configurations ({2D, 3D} × {isotropic, anisotropic} × {dilation, friction, both}),
comparing damage states, softening exponents, contact traction, displacement jump,
friction bound and fracture gap:

Check Result
tangent_dilation_angle extraction bit-identical, all 80 arrays
Mixin merge bit-identical, all 80 arrays
Example gap reparameterisation traction, bound and damage state bit-identical; history to 2.8e-15

The law itself has no neutrality gate, so the substitutes are exact identities:

  • Patton recovery. μ* → tan(φ_b + ψ₀) as σ_n → 0 and μ* → μ_b + μ_p0 at
    σ_n = σ_T, both with Λ = 0. Ties the partition, the dilation scaling and the tangent
    addition to one closed form that none of them contains.
  • Partition bounds, including σ_n > σ_T. This is the clip-before-power test: with the
    clip applied afterwards the base is negative and a non-integer power of it is complex,
    so the failure is not a wrong number.
  • Smoothness at σ_T asserted as an observed rate: quartering the step halves the
    centred difference, pinning K − 1 = 0.5 in the derivative. A hard switch would give a
    quotient growing as 1/h, a linear ramp one constant in h.
  • Dissipation positivity over a (σ_n, Λ) grid, against
    friction_coefficient − tangent_dilation_angle.
  • Pole guard raises at setup for μ_b·tanψ₀ ≥ 1, and does not fire for an admissible
    steep angle.

pytest tests/models/ tests/compositional/ tests/numerics/: 2068 passed, 353 skipped,
1 xfailed.

The retuned tolerance is the one place the new law required an existing test to change.
test_fracture_damage.py compares the fourth-step damage length against the prescribed
tangential boundary displacement, which the plastic jump only approaches — part of the
motion is taken up elastically, and that share grows with the friction coefficient. With
the floor at μ_b the shortfall goes from 0.208% to 0.306%, crossing an rtol of 3e-3
that had little margin to begin with. Widened to 1e-2, which still catches a missing
absolute value, a wrong projection or a spurious factor.

Two notes for review

The API: commit overlaps #1762. σ_T needs to be an Operator rather than a
Scalar so a heterogeneous asperity strength stays expressible, and the same argument
applies to the wear energy scales and residual damage accessors introduced in #1762. They
are widened here rather than by amending #1762, to avoid force-pushing a PR under review —
so #1762's reviewer sees signatures this branch changes three commits later.

MAINT: Remove the spurious mated gap is a prerequisite, not housekeeping. The damage
example inherited fracture_gap = 1e-3 from granite, cancelled by a normal boundary
displacement of 0.98e-3. Once the mated gap is damageable, (1 − d₀^d)·g₀ = 4e-4 m of
aperture collapse against a 2e-5 m contact margin diverges at the first time step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant