Calibrated scalar strain-life assessment¶
constitutive.CoffinMansonBasquinCurve describes the combined elastic and
plastic strain-amplitude relation
N is full cycles to failure; 2 N is reversals. The strain contributions
are added, not the lives. Strain is dimensionless, not percent. The stress
coefficient and Young's modulus must use the same declared unit. The
COMSOL theory description
documents this conventional relation and the importance of the selected
strain measure and mean stress. AgentFEM's initial scope is narrower: one
signed scalar total mechanical strain component, not a multiaxial criterion.
from agentfem import constitutive
# Synthetic values for demonstrating the interface, NOT design data.
curve = constitutive.CoffinMansonBasquinCurve(
young=200_000.0,
fatigue_strength_coefficient=1_000.0,
fatigue_strength_exponent=-0.1,
fatigue_ductility_coefficient=0.5,
fatigue_ductility_exponent=-0.6,
calibrated_cycles=(1.0, 1.0e8),
stress_unit="MPa",
source="synthetic example; not material calibration",
)
assessment = constitutive.assess_strain_history(
[-0.01, 0.01, -0.01],
curve,
strain_measure="mechanical_total",
source="signed axial mechanical strain at the selected material point",
mean_stress_correction="none",
)
print(assessment.as_dict())
Declaring the calibration domain¶
The constructor above declares a cycle-count domain. For strain-controlled
data whose reviewed applicability is an amplitude interval, use
CoffinMansonBasquinCurve.from_strain_domain(...) with the same coefficients,
unit and source, replacing calibrated_cycles with
calibrated_strain_amplitudes=(minimum_amplitude, maximum_amplitude).
These are total mechanical strain amplitudes in dimensionless units.
This explicit alternative derives the corresponding cycle endpoints from the curve. Observed life extrema need not equal fitted endpoint predictions: experimental scatter is not itself an extrapolation boundary. The declared amplitude interval must still be justified by the material data; the software does not infer or widen it. Output records distinguish the declared amplitude domain from model-implied cycle bounds. Changing coefficients requires rebuilding this curve so its derived bounds remain consistent.
Input and failure contract¶
- Supply a signed mechanical strain history with enough accepted samples to resolve its reversals. Sparse visualization frames are not automatically a sufficient fatigue history. Thermal strain must already be excluded.
- Do not use accumulated PEEQ/CEEQ or a positive strain norm as a substitute for a reversing signed component. The caller declares the measure; the software cannot recover a missing tensor or infer physical semantics from unlabeled numbers.
- An explicit calibration domain and provenance are mandatory. A counted amplitude outside those bounds raises an error; there is no hidden clipping, extrapolation, or endurance-limit inference.
- The caller must explicitly select
mean_stress_correction="none". Means remain visible in the counted cycles. This is not evidence that mean-stress effects are negligible. Morrow/SWT require their own paired stress/strain contract and are not implemented here. - The existing scalar rainflow algorithm is reused. Remaining excursions count
as half cycles. Miner damage is a postprocessing assumption, not constitutive
damage. A constant sampled history returns no counted damage; strict JSON
reports
repeated_history_life: null, not a claim of infinite service life.
Composition and evidence¶
For a reviewed isothermal tensile rupture table, use
assessments.TabulatedRuptureCurve instead of writing an interpolation callback:
from agentfem import assessments
# Synthetic illustration, not P92 or design data.
rupture = assessments.TabulatedRuptureCurve(
stresses=(40.0, 100.0), rupture_times=(2500.0, 1000.0),
temperature=800.0, stress_unit="MPa", time_unit="s",
stress_measure="signed_axial", material_condition="synthetic",
failure_definition="synthetic rupture", source="analytic t=100000/sigma",
)
print(rupture(60.0, 800.0))
Supply this as rupture_time= to assessments.creep_damage_from_result, with
the same units and stress measure and rupture_source=rupture.source. The
assessment retains the complete curve. Interpolation is linear in log stress
and log life; temperature is fixed in kelvin. Stress outside the table or a
different temperature is rejected. Tables must already be reviewed into a
monotone curve: repeated tests and scatter are not silently averaged. This
does not fit a creep mechanism, interpolate between temperatures or supply
an engineering allowable. Existing user-owned rupture callables remain valid.
Pass the strain-life assessment explicitly as fatigue= to assessments.creep_fatigue,
together with source-identified creep time fractions and the intended
interaction diagram. assessments.creep_damage_from_result provides
time-resolved creep fractions for declared, nonoverlapping dwell intervals;
its stress/temperature/time units and rupture source are explicit. Do not
replace a resolved relaxation history by its maximum when evaluating the
actual time integral. The existing creep_fatigue_from_result convenience
function remains stress-life based; it does not silently reinterpret its
history as strain. The reference linear interaction is transparent, not a
design-code acceptance curve. A combined assessment does not feed damage back
into equilibrium, and does not prove absence of double-counting when the
supplied strain-life calibration already includes dwell effects.
For a nonlinear rupture relation, compare quadrature_subdivisions=1, 2, 4
in creep_damage_from_result to check integration sensitivity on the same
piecewise-linear stress/temperature histories. This explicitly refines every
union-grid interval, preserves original knots, and records the subdivision
count. It does not add physical samples or reduce the reported source gaps;
maximum_source_interval still checks the original histories. The supported
integer range is 1–1024 per interval. Numerical time resolution must permit the
requested subdivision. No automatic error certificate is inferred.
The current tests cover equal-exponent closed-form inversion, round trips, stress-unit invariance, full/half-cycle conventions, calibration rejection, source retention and composition. They do not validate a material's fitted parameters, nonisothermal life, multiaxial damage or component service life.
The verification ladder adds structural relaxation, a classical cyclic hysteresis reference and a traceable standards and experimental-data map. Interaction acceptance requires diagram-domain coverage even when the fatigue damage is zero; it is not regulatory approval.