download
raw
6.82 kB
"""
Dang Van multiaxial fatigue criterion computation.
Algorithm based on old/deviatoire.py and old/versDV.py:
- For each time step, compute hydrostatic pressure sigma_H
- For each time step, compute max shear stress tau_max by scanning all facets (theta, phi)
- Plot (sigma_H, tau_max) cloud and criterion line: tau = b - a * sigma_H
Inputs:
- stress_series: list of stress tensors (Voigt 6: [sxx, syy, szz, sxy, sxz, syz])
- a, b: Dang Van material parameters
Outputs:
- dict with points (sigma_H, tau_max) for plotting and safety assessment
"""
import math
import numpy as np
def tens_to_mat(tens):
"""Convert Voigt 6-component tensor to 3x3 symmetric matrix.
Voigt notation: [sxx, syy, szz, sxy, sxz, syz]
Matrix:
[[sxx, sxy, sxz],
[sxy, syy, syz],
[sxz, syz, szz]]
"""
if len(tens) == 6:
sxx, syy, szz, sxy, sxz, syz = tens
return np.array([
[sxx, sxy, sxz],
[sxy, syy, syz],
[sxz, syz, szz]
])
elif len(tens) == 3 and hasattr(tens[0], '__len__') and len(tens[0]) == 3:
# Already a 3x3 matrix
return np.array(tens)
else:
raise ValueError("Tensor must be Voigt 6-component or 3x3 matrix")
def hydro(tens):
"""Compute hydrostatic pressure sigma_H = (sxx + syy + szz) / 3."""
if hasattr(tens, '__len__'):
if len(tens) == 6:
return (tens[0] + tens[1] + tens[2]) / 3.0
elif len(tens) == 3 and hasattr(tens[0], '__len__'):
# 3x3 matrix
return (tens[0][0] + tens[1][1] + tens[2][2]) / 3.0
raise ValueError("Invalid tensor format")
def normale(theta, phi):
"""Return unit normal vector for facet defined by angles (theta, phi)."""
return np.array([
math.cos(theta) * math.sin(phi),
math.sin(theta) * math.sin(phi),
math.cos(phi)
])
def cont_tang(tens, vN):
"""Compute tangential stress vector on facet with normal vN.
Args:
tens: stress tensor (Voigt 6 or 3x3)
vN: unit normal vector
Returns:
tangential stress vector
"""
M = tens_to_mat(tens)
cont = M @ vN # stress vector on facet
cN = np.dot(cont, vN) # normal component
contT = cont - cN * vN # tangential component
return contT
def amplitude_tang_max(tens, pas_deg=2):
"""Compute maximum tangential stress amplitude by scanning all facets.
Args:
tens: stress tensor (Voigt 6 or 3x3)
pas_deg: angular step in degrees (default 2 for speed, use 1 for precision)
Returns:
[max_tau, [theta_max, phi_max]]
"""
maxi = 0.0
plan_max = [0.0, 0.0]
pas = math.pi / (180 / pas_deg)
n_steps = int(180 / pas_deg) + 1
for i in range(n_steps):
theta = i * pas
for j in range(n_steps):
phi = j * pas
vN = normale(theta, phi)
contT = cont_tang(tens, vN)
norme = np.linalg.norm(contT)
if norme > maxi:
maxi = norme
plan_max = [theta, phi]
return [maxi, plan_max]
def compute_dang_van(stress_series, a, b, pas_deg=2):
"""Compute Dang Van criterion for a stress tensor series.
The Dang Van criterion states that fatigue failure occurs when:
tau_max + a * sigma_H > b
This function computes for each time step:
- sigma_H: hydrostatic pressure
- tau_max: maximum shear stress (by scanning all facets)
Args:
stress_series: list of stress tensors (Voigt 6: [sxx, syy, szz, sxy, sxz, syz])
a: slope parameter (typically ~0.3)
b: intercept parameter (fatigue limit in pure shear)
pas_deg: angular step in degrees for facet scanning (default 2)
Returns:
dict with:
- points: list of {sigma_H, tau_max, dv} for each time step
- dv_max: maximum DV value
- safe: True if all points satisfy criterion
- margin: b - dv_max
- a, b: parameters used
- criterion_line: points for plotting the criterion line
"""
if stress_series is None or len(stress_series) == 0:
raise ValueError("stress_series is required and must not be empty")
try:
a = float(a)
b = float(b)
except Exception as exc:
raise ValueError("Parameters a and b must be floats") from exc
points = []
dv_max = -float("inf")
index_max = -1
for i, tens in enumerate(stress_series):
# Convert to list/array if needed
if hasattr(tens, 'tolist'):
tens = tens.tolist()
tens = [float(x) for x in tens]
# Compute hydrostatic pressure
sigma_H = hydro(tens)
# Compute max shear stress by scanning facets
tau_max, _ = amplitude_tang_max(tens, pas_deg)
# Dang Van criterion value
dv = tau_max + a * sigma_H
points.append({
"i": i,
"sigma_H": float(sigma_H),
"tau_max": float(tau_max),
"dv": float(dv)
})
if dv > dv_max:
dv_max = dv
index_max = i
# Determine if safe (all DV values <= b)
safe = dv_max <= b
# Generate criterion line for plotting
# Line: tau = b - a * sigma_H
sigma_H_values = [p["sigma_H"] for p in points]
sigma_H_min = min(sigma_H_values) if sigma_H_values else 0
sigma_H_max_val = max(sigma_H_values) if sigma_H_values else 100
# Extend range a bit for visualization
margin_range = (sigma_H_max_val - sigma_H_min) * 0.2 if sigma_H_max_val != sigma_H_min else 10
line_start = sigma_H_min - margin_range
line_end = sigma_H_max_val + margin_range
criterion_line = [
{"sigma_H": float(line_start), "tau": float(b - a * line_start)},
{"sigma_H": float(line_end), "tau": float(b - a * line_end)}
]
return {
"points": points,
"dv_max": float(dv_max),
"index_max": int(index_max),
"safe": bool(safe),
"margin": float(b - dv_max),
"a": float(a),
"b": float(b),
"criterion_line": criterion_line
}
if __name__ == "__main__":
# Test with sample data
sigma1 = 100
omega = 2 * math.pi
pas_temps = 0.01
fin = 1.0
stress_series = []
for i in range(int(fin / pas_temps)):
t = i * pas_temps
tens = [sigma1 * math.cos(omega * t), 0, 0, 0, 0, 0]
stress_series.append(tens)
result = compute_dang_van(stress_series, a=0.3, b=50)
print(f"DV max: {result['dv_max']:.2f}")
print(f"Safe: {result['safe']}")
print(f"Margin: {result['margin']:.2f}")
print(f"Number of points: {len(result['points'])}")

Xet Storage Details

Size:
6.82 kB
·
Xet hash:
766f079d7107a4318354b4a2bde19d893732eaa1f9cf7744ace23a140cdcb5d0

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.