ℹ️ General Information
Component Name: Minimum Circumscribed Circle / Ellipse — sampled stress path
Component Location: core/multiaxial/stress_path.py
Suggested Python Name: calc_mcc_from_path, calc_mce_from_path
FABER WG Relation: WG4.1
Priority: (1-10 scale) 5
Technical Complexity: (1-10 scale) 6
Estimated Effort: (1-10 scale) 6
Dependencies:
- Shared enclosure helpers in the same module (Welzl for MCC, Khachiyan / Löwner–John for MCE).
- Shared
PathMeasure return type, defined once and reused by the analytical sibling.
Related Issues:
- Sibling issue (analytical / harmonic input → closed-form MCC, MCE): TBD. Same module, same
PathMeasure output, cross-validated against this one.
📋 Problem Description
Enclose a sampled (discretized) shear-stress path on a material plane and return its Minimum Circumscribed Circle (MCC) and Minimum Circumscribed Ellipse (MCE) as measures of shear-stress amplitude (and, for the MCE, non-proportionality) used by multiaxial high-cycle-fatigue criteria.
The input is the resolved shear-stress vector sampled over the loading history — a real, possibly non-harmonic and non-proportional path. The same functions must work both for a 2D resolved-shear path on a physical plane (d = 2) and for the path in the 5D Ilyushin deviatoric space (d = 5); dimensionality is carried by the input array, not by the algorithm.
This is the general/numerical counterpart to the analytical (harmonic) sibling issue. Both return the identical PathMeasure, and the analytical result must agree with a densely-sampled run of these functions (see Validation).
Mathematical Formulation
MCC (minimum enclosing ball):
$$
\tau_a = \min_{\mathbf{c}} \ \max_{i} \ \lVert \boldsymbol{\tau}_i - \mathbf{c} \rVert , \qquad \boldsymbol{\tau}_i \in \mathbb{R}^d
$$
MCE (Löwner–John minimum-volume enclosing ellipsoid):
$$
\min_{\mathbf{A} \succ 0, \ \mathbf{c}} \ -\ln\det \mathbf{A} \quad \text{s.t.} \quad (\boldsymbol{\tau}_i - \mathbf{c})^{\mathsf{T}} \mathbf{A} (\boldsymbol{\tau}_i - \mathbf{c}) \le 1 \ \ \forall i
$$
with semi-axes $R_k = 1/\sqrt{\lambda_k(\mathbf{A})}$ ordered $R_a \ge R_b \ge \dots$, shear-stress amplitude $\tau_a = \sqrt{\sum_k R_k^2}$, and non-proportionality factor $f_{np} = R_b / R_a \in [0, 1]$.
Latex text:
MCC:
$$
\tau_a = \min_{\mathbf{c}} \ \max_{i} \ \lVert \boldsymbol{\tau}_i - \mathbf{c} \rVert
$$
MCE:
$$
\min_{\mathbf{A} \succ 0, \ \mathbf{c}} \ -\ln\det \mathbf{A} \quad \text{s.t.} \quad (\boldsymbol{\tau}_i - \mathbf{c})^{\mathsf{T}} \mathbf{A} (\boldsymbol{\tau}_i - \mathbf{c}) \le 1 \ \ \forall i
$$
R_k = 1 / sqrt(lambda_k(A)), tau_a = sqrt(sum_k R_k^2), f_np = R_b / R_a
🔧 Implementation Guideline
Function Signature
from dataclasses import dataclass
import numpy as np
from numpy.typing import ArrayLike, NDArray
# Module defaults (shared by callers and tests).
_TOL: float = 1e-9
_MAX_ITER: int = 10_000
_AXIS_FLOOR: float = 1e-9
@dataclass(frozen=True)
class PathMeasure:
"""Result of enclosing a stress path; shared by the sampled and analytical routes.
Attributes:
center: Mean component (ball / ellipsoid centre), shape (d,). Always present.
amplitude: Shear-stress amplitude tau_a (sqrt(J2,a)). Always present.
semi_axes: Principal radii Ra >= Rb >= ..., shape (d,). None for the circle.
nonproportionality_factor: Rb / Ra in [0, 1]. None for the circle.
"""
center: NDArray[np.float64]
amplitude: float
semi_axes: NDArray[np.float64] | None = None
nonproportionality_factor: float | None = None
def calc_mcc_from_path(path: ArrayLike, tol: float = _TOL) -> PathMeasure:
"""Minimum Circumscribed Circle / Hypersphere of a sampled shear-stress path.
Treats the path as an unordered point set in R^d and returns the smallest
enclosing ball (exact, via Welzl). The radius is the shear-stress amplitude;
a circle carries no shape information, so semi_axes and
nonproportionality_factor are None. Works unchanged for d = 2 and d = 5.
Args:
path: Array-like of shape (N, d). Sampled shear-stress path (d = 2 on a
physical plane, d = 5 in Ilyushin space). MPa.
tol: Relative tolerance for the point-in-ball inclusion test. The solver
is exact, so there is no iteration cap.
Returns:
PathMeasure with center and amplitude; semi_axes and
nonproportionality_factor are None.
Raises:
ValueError: If path is empty, not 2-D (N, d) with d >= 2, or non-finite.
"""
pass # Implementation goes here
def calc_mce_from_path(
path: ArrayLike,
tol: float = _TOL,
max_iter: int = _MAX_ITER,
axis_floor: float = _AXIS_FLOOR,
) -> PathMeasure:
"""Minimum Circumscribed Ellipse / Ellipsoid (Loewner-John) of a sampled path.
Returns the minimum-volume enclosing ellipsoid (Khachiyan). Semi-axes are the
principal radii Ra >= Rb >= ...; amplitude = sqrt(sum Rk^2);
nonproportionality_factor = Rb / Ra. Works unchanged for d = 2 and d = 5.
Args:
path: Array-like of shape (N, d), as in calc_mcc_from_path. MPa.
tol: Convergence tolerance for the Khachiyan iteration.
max_iter: Iteration cap.
axis_floor: Lower bound on the smallest semi-axis for (near-)proportional
paths, where it tends to zero. Stabilises numerics only;
nonproportionality_factor still reports ~0.
Returns:
PathMeasure with center, amplitude, semi_axes and
nonproportionality_factor.
Raises:
ValueError: If path is empty, not 2-D (N, d) with d >= 2, or non-finite.
Warns:
UserWarning: If the iteration did not converge within max_iter.
UserWarning: If the path is (near-)degenerate and axis_floor was engaged.
"""
pass # Implementation goes here
Inputs
| Parameter |
Symbol |
Type |
Description |
Units |
Constraints |
| path |
$\boldsymbol{\tau}_i$ |
array of floats, shape $(N, d)$
|
Sampled shear-stress path; $d = 2$ (physical plane) or $d = 5$ (Ilyushin) |
MPa |
$N \ge 1$, $d \ge 2$, finite |
| tol |
— |
float |
Relative tolerance (inclusion test for MCC, convergence for MCE) |
— |
$> 0$ |
| max_iter |
— |
int |
Iteration cap (MCE only) |
— |
$> 0$ |
| axis_floor |
— |
float |
Lower bound on the smallest semi-axis (MCE only) |
MPa |
$\ge 0$ |
Outputs
| Parameter |
Symbol |
Type |
Description |
Units |
Range |
| center |
$\mathbf{c}$ |
array of floats, $(d,)$
|
Mean component (centre) |
MPa |
$(-\infty; \infty)$ |
| amplitude |
$\tau_a$ |
float |
Shear-stress amplitude |
MPa |
$[0; \infty)$ |
| semi_axes |
$R_k$ |
array of floats $(d,)$ or None
|
Principal radii $R_a \ge R_b \ge \dots$ (MCE only) |
MPa |
$[0; \infty)$ |
| nonproportionality_factor |
$f_{np}$ |
float or None
|
$R_b / R_a$ (MCE only) |
— |
$[0; 1]$ |
Expected Behavior
- Accept
(N, d) input for any d >= 2; the same code path serves d = 2 and d = 5.
- Treat the path as an unordered point set: results invariant to sample reordering and to duplicate samples.
calc_mcc_from_path populates center and amplitude; semi_axes and nonproportionality_factor are None.
calc_mce_from_path populates all four fields, with semi_axes sorted descending.
- Single unique point (or all-coincident samples):
amplitude = 0.
- Proportional (collinear) path: MCE smallest semi-axis tends to zero,
nonproportionality_factor approximately 0; axis_floor keeps the shape well-defined.
- Circular path (equal-amplitude 90-degree out-of-phase):
nonproportionality_factor approximately 1.
Error Handling
ValueError for empty input, non-2D input, d < 2, or non-finite values.
- MCC uses an exact solver and does not warn on non-convergence.
- MCE raises
UserWarning if the Khachiyan iteration does not converge within max_iter, and UserWarning if the path is (near-)degenerate and axis_floor was engaged.
✅ Validation & Testing
Test Cases
| Test Case |
Inputs |
Expected Outputs |
Notes |
| 1 |
Proportional segment $(-100, 0) \to (100, 0)$
|
MCC: center $(0, 0)$, amplitude $100$. MCE: $R_a = 100$, $R_b \approx 0$ (floored), $f_{np} \approx 0$
|
straight-line / proportional |
| 2 |
Circular path $(100\cos\theta, 100\sin\theta)$
|
MCC: amplitude $100$. MCE: $R_a = R_b = 100$, $f_{np} = 1$, amplitude $\approx 141.42$
|
90-deg out-of-phase, equal amplitude |
| 3 |
Elliptical path $R_a = 100$, $R_b = 40$
|
MCC: amplitude $100$. MCE: $R_a = 100$, $R_b = 40$, $f_{np} = 0.4$, amplitude $\approx 107.70$
|
general non-proportional |
| 4 |
Single point $(50, 30)$ (repeated) |
MCC and MCE: amplitude $0$, center $(50, 30)$
|
degenerate point |
| 5 |
5D Ilyushin sphere of radius $70$
|
MCC: amplitude $70$
|
confirms d = 5 on the same code path |
Additional checks:
- Invariance to sample reordering (shuffle rows) and to duplicated samples.
ValueError raised for empty, non-2D, d < 2, and non-finite inputs.
UserWarning raised when the MCE iteration does not converge within max_iter.
UserWarning raised when a (near-)proportional path engages axis_floor.
- Cross-validation: a densely sampled harmonic biaxial path matches the closed-form ellipse (semi-axes equal the singular values of the generating matrix; MCC radius equals the largest singular value). When the analytical sibling lands, compare against
calc_mce_from_harmonics / calc_mcc_from_harmonics.
Acceptance Criteria
📚 References & Resources
- Papadopoulos, I.V. (1998). Critical plane approaches in high-cycle fatigue: on the definition of the amplitude and mean value of the shear stress acting on the critical plane. Fatigue Fract. Eng. Mater. Struct. 21, 269–285. — MCC / √J₂,ₐ definition.
- Zouain, N., Mamiya, E.N., Comes, F. (2006). Using enclosing ellipsoids in multiaxial fatigue strength criteria. Eur. J. Mech. A/Solids 25, 51–71. — MCE in multiaxial fatigue.
- Papuga, J. et al. (2021). Validating the Methods to Process the Stress Path in Multiaxial High-Cycle Fatigue Criteria. Materials 14(1), 206. — comparison and analytical harmonic solutions.
- Welzl, E. (1991). Smallest enclosing disks (balls and ellipsoids). LNCS 555, 359–370. — MCC algorithm.
- Moshtagh, N. (2005). Minimum volume enclosing ellipsoid (Khachiyan algorithm). — MCE algorithm reference implementation lineage.
ℹ️ General Information
Component Name: Minimum Circumscribed Circle / Ellipse — sampled stress path
Component Location:
core/multiaxial/stress_path.pySuggested Python Name:
calc_mcc_from_path,calc_mce_from_pathFABER WG Relation: WG4.1
Priority: (1-10 scale) 5
Technical Complexity: (1-10 scale) 6
Estimated Effort: (1-10 scale) 6
Dependencies:
PathMeasurereturn type, defined once and reused by the analytical sibling.Related Issues:
PathMeasureoutput, cross-validated against this one.📋 Problem Description
Enclose a sampled (discretized) shear-stress path on a material plane and return its Minimum Circumscribed Circle (MCC) and Minimum Circumscribed Ellipse (MCE) as measures of shear-stress amplitude (and, for the MCE, non-proportionality) used by multiaxial high-cycle-fatigue criteria.
The input is the resolved shear-stress vector sampled over the loading history — a real, possibly non-harmonic and non-proportional path. The same functions must work both for a 2D resolved-shear path on a physical plane (
d = 2) and for the path in the 5D Ilyushin deviatoric space (d = 5); dimensionality is carried by the input array, not by the algorithm.This is the general/numerical counterpart to the analytical (harmonic) sibling issue. Both return the identical
PathMeasure, and the analytical result must agree with a densely-sampled run of these functions (see Validation).Mathematical Formulation
MCC (minimum enclosing ball):
MCE (Löwner–John minimum-volume enclosing ellipsoid):
with semi-axes$R_k = 1/\sqrt{\lambda_k(\mathbf{A})}$ ordered $R_a \ge R_b \ge \dots$ , shear-stress amplitude $\tau_a = \sqrt{\sum_k R_k^2}$ , and non-proportionality factor $f_{np} = R_b / R_a \in [0, 1]$ .
Latex text:
🔧 Implementation Guideline
Function Signature
Inputs
Outputs
NoneNoneExpected Behavior
(N, d)input for anyd >= 2; the same code path servesd = 2andd = 5.calc_mcc_from_pathpopulatescenterandamplitude;semi_axesandnonproportionality_factorareNone.calc_mce_from_pathpopulates all four fields, withsemi_axessorted descending.amplitude = 0.nonproportionality_factorapproximately0;axis_floorkeeps the shape well-defined.nonproportionality_factorapproximately1.Error Handling
ValueErrorfor empty input, non-2D input,d < 2, or non-finite values.UserWarningif the Khachiyan iteration does not converge withinmax_iter, andUserWarningif the path is (near-)degenerate andaxis_floorwas engaged.✅ Validation & Testing
Test Cases
d = 5on the same code pathAdditional checks:
ValueErrorraised for empty, non-2D,d < 2, and non-finite inputs.UserWarningraised when the MCE iteration does not converge withinmax_iter.UserWarningraised when a (near-)proportional path engagesaxis_floor.calc_mce_from_harmonics/calc_mcc_from_harmonics.Acceptance Criteria
calc_mcc_from_pathandcalc_mce_from_pathreturn the sharedPathMeasured = 2andd = 5📚 References & Resources