delta-theory 8.1.2__py3-none-any.whl → 8.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core/__init__.py +111 -57
- core/__main__.py +194 -129
- core/unified_flc_v8_1.py +765 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.0.dist-info}/METADATA +1 -1
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.0.dist-info}/RECORD +9 -9
- core/unified_flc_v7.py +0 -727
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.0.dist-info}/WHEEL +0 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.0.dist-info}/entry_points.txt +0 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.0.dist-info}/licenses/LICENSE +0 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.0.dist-info}/top_level.txt +0 -0
core/unified_flc_v7.py
DELETED
|
@@ -1,727 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""δ-Theory Unified FLC & Forming-Fatigue Integration (v7.2 + v8.0)
|
|
3
|
-
|
|
4
|
-
FLC Model (v7.2):
|
|
5
|
-
- Free volume consumption approach
|
|
6
|
-
- FLC(β) = FLC₀_pure × (1 - η_total) × h(β, R, τ/σ)
|
|
7
|
-
- Supports: BCC, FCC, HCP with strengthening mechanisms
|
|
8
|
-
|
|
9
|
-
Forming-Fatigue Integration (v8.0):
|
|
10
|
-
- r_th_eff = r_th_virgin × (1 - η_forming)
|
|
11
|
-
- Predicts fatigue life reduction due to forming history
|
|
12
|
-
|
|
13
|
-
Usage:
|
|
14
|
-
from unified_flc_v7 import FLCPredictor, FormingFatigueIntegrator
|
|
15
|
-
|
|
16
|
-
# FLC prediction
|
|
17
|
-
flc = FLCPredictor()
|
|
18
|
-
Em = flc.predict(beta=0.0, material='SPCC')
|
|
19
|
-
|
|
20
|
-
# Forming-fatigue integration
|
|
21
|
-
integrator = FormingFatigueIntegrator()
|
|
22
|
-
r_th_eff = integrator.effective_r_th(eta_forming=0.4, structure='BCC')
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
from __future__ import annotations
|
|
26
|
-
|
|
27
|
-
import warnings
|
|
28
|
-
from dataclasses import dataclass, field
|
|
29
|
-
from typing import Dict, List, Literal, Optional, Tuple, Union
|
|
30
|
-
import numpy as np
|
|
31
|
-
|
|
32
|
-
# Try to import from v6.9
|
|
33
|
-
try:
|
|
34
|
-
from .unified_yield_fatigue_v6_9 import (
|
|
35
|
-
Material, MATERIALS,
|
|
36
|
-
T_TWIN, R_COMP,
|
|
37
|
-
sigma_base_delta,
|
|
38
|
-
)
|
|
39
|
-
V69_AVAILABLE = True
|
|
40
|
-
except ImportError:
|
|
41
|
-
try:
|
|
42
|
-
# Standalone mode (not as package)
|
|
43
|
-
from unified_yield_fatigue_v6_9 import (
|
|
44
|
-
Material, MATERIALS,
|
|
45
|
-
T_TWIN, R_COMP,
|
|
46
|
-
sigma_base_delta,
|
|
47
|
-
)
|
|
48
|
-
V69_AVAILABLE = True
|
|
49
|
-
except ImportError:
|
|
50
|
-
V69_AVAILABLE = False
|
|
51
|
-
warnings.warn("v6.9 not found. Using built-in material database.")
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# ==============================================================================
|
|
55
|
-
# Constants
|
|
56
|
-
# ==============================================================================
|
|
57
|
-
|
|
58
|
-
# Crystal structure fatigue thresholds (from v6.10)
|
|
59
|
-
R_TH_VIRGIN = {
|
|
60
|
-
'BCC': 0.65,
|
|
61
|
-
'FCC': 0.02,
|
|
62
|
-
'HCP': 0.20,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
# Slip system counts (affects FLC shape)
|
|
66
|
-
N_SLIP = {
|
|
67
|
-
'BCC': 48, # {110}<111>:12 + {112}<111>:12 + {123}<111>:24
|
|
68
|
-
'FCC': 12, # {111}<110>
|
|
69
|
-
'HCP': 3, # Basal plane (room temperature)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
# τ/σ ratios (from v5.0)
|
|
73
|
-
TAU_SIGMA = {
|
|
74
|
-
'Fe': 0.565, 'Cu': 0.565, 'Al': 0.565, 'Ni': 0.565,
|
|
75
|
-
'Ti': 0.546, 'Mg': 0.327, 'Zn': 0.480,
|
|
76
|
-
'BCC': 0.565, 'FCC': 0.565, 'HCP': 0.50,
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
# R_comp ratios (from v5.0)
|
|
80
|
-
R_COMPRESSION = {
|
|
81
|
-
'Fe': 1.00, 'Cu': 1.00, 'Al': 1.00, 'Ni': 1.00,
|
|
82
|
-
'Ti': 1.00, 'Mg': 0.60, 'Zn': 1.20,
|
|
83
|
-
'BCC': 1.00, 'FCC': 1.00, 'HCP': 0.80,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# ==============================================================================
|
|
88
|
-
# Material Database for FLC (extended)
|
|
89
|
-
# ==============================================================================
|
|
90
|
-
|
|
91
|
-
@dataclass
|
|
92
|
-
class FLCMaterial:
|
|
93
|
-
"""Material data for FLC prediction."""
|
|
94
|
-
name: str
|
|
95
|
-
structure: Literal['BCC', 'FCC', 'HCP']
|
|
96
|
-
|
|
97
|
-
# v5.0 base parameters
|
|
98
|
-
f_d: float # d-electron directionality factor
|
|
99
|
-
E_bond: float # Bond energy [eV]
|
|
100
|
-
sigma_y: float # Yield stress [MPa]
|
|
101
|
-
|
|
102
|
-
# Multiaxial parameters
|
|
103
|
-
tau_sigma: float = 0.565 # τ/σ ratio
|
|
104
|
-
R_comp: float = 1.0 # Compression/tension ratio
|
|
105
|
-
|
|
106
|
-
# Strengthening mechanisms (free volume consumption)
|
|
107
|
-
C_ss: float = 0.0 # Solid solution concentration
|
|
108
|
-
f_ppt: float = 0.0 # Precipitate/martensite fraction
|
|
109
|
-
rho_d: float = 1e12 # Dislocation density [m^-2]
|
|
110
|
-
d_grain: float = 50e-6 # Grain size [m]
|
|
111
|
-
|
|
112
|
-
@property
|
|
113
|
-
def r_th(self) -> float:
|
|
114
|
-
"""Virgin material fatigue threshold."""
|
|
115
|
-
return R_TH_VIRGIN[self.structure]
|
|
116
|
-
|
|
117
|
-
@property
|
|
118
|
-
def n_slip(self) -> int:
|
|
119
|
-
"""Number of slip systems."""
|
|
120
|
-
return N_SLIP[self.structure]
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# Built-in material database
|
|
124
|
-
FLC_MATERIALS: Dict[str, FLCMaterial] = {
|
|
125
|
-
# BCC steels
|
|
126
|
-
'SPCC': FLCMaterial(
|
|
127
|
-
'SPCC', 'BCC', f_d=1.5, E_bond=4.28, sigma_y=200,
|
|
128
|
-
tau_sigma=0.565, R_comp=1.00,
|
|
129
|
-
C_ss=0.02, f_ppt=0.0, rho_d=1e13, d_grain=20e-6
|
|
130
|
-
),
|
|
131
|
-
'DP590': FLCMaterial(
|
|
132
|
-
'DP590', 'BCC', f_d=1.5, E_bond=4.28, sigma_y=590,
|
|
133
|
-
tau_sigma=0.565, R_comp=1.00,
|
|
134
|
-
C_ss=0.08, f_ppt=0.15, rho_d=1e14, d_grain=5e-6
|
|
135
|
-
),
|
|
136
|
-
'SECD-E16': FLCMaterial(
|
|
137
|
-
'SECD-E16', 'BCC', f_d=1.5, E_bond=4.28, sigma_y=300,
|
|
138
|
-
tau_sigma=0.565, R_comp=1.00,
|
|
139
|
-
C_ss=0.03, f_ppt=0.0, rho_d=1e13, d_grain=15e-6
|
|
140
|
-
),
|
|
141
|
-
|
|
142
|
-
# FCC metals/alloys
|
|
143
|
-
'Al': FLCMaterial(
|
|
144
|
-
'Al', 'FCC', f_d=1.6, E_bond=3.39, sigma_y=35,
|
|
145
|
-
tau_sigma=0.565, R_comp=1.00,
|
|
146
|
-
C_ss=0.01, f_ppt=0.0, rho_d=1e12, d_grain=50e-6
|
|
147
|
-
),
|
|
148
|
-
'Cu': FLCMaterial(
|
|
149
|
-
'Cu', 'FCC', f_d=2.0, E_bond=3.49, sigma_y=70,
|
|
150
|
-
tau_sigma=0.565, R_comp=1.00,
|
|
151
|
-
C_ss=0.0, f_ppt=0.0, rho_d=1e12, d_grain=50e-6
|
|
152
|
-
),
|
|
153
|
-
'SUS304': FLCMaterial(
|
|
154
|
-
'SUS304', 'FCC', f_d=2.6, E_bond=4.44, sigma_y=250,
|
|
155
|
-
tau_sigma=0.565, R_comp=1.00,
|
|
156
|
-
C_ss=0.25, f_ppt=0.0, rho_d=1e13, d_grain=30e-6
|
|
157
|
-
),
|
|
158
|
-
|
|
159
|
-
# HCP metals/alloys
|
|
160
|
-
'Ti': FLCMaterial(
|
|
161
|
-
'Ti', 'HCP', f_d=5.7, E_bond=4.85, sigma_y=275,
|
|
162
|
-
tau_sigma=0.546, R_comp=1.00,
|
|
163
|
-
C_ss=0.02, f_ppt=0.0, rho_d=1e13, d_grain=30e-6
|
|
164
|
-
),
|
|
165
|
-
'Mg_AZ31': FLCMaterial(
|
|
166
|
-
'Mg_AZ31', 'HCP', f_d=8.2, E_bond=1.51, sigma_y=160,
|
|
167
|
-
tau_sigma=0.327, R_comp=0.60,
|
|
168
|
-
C_ss=0.05, f_ppt=0.02, rho_d=1e13, d_grain=15e-6
|
|
169
|
-
),
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
# ==============================================================================
|
|
174
|
-
# FLC Predictor (v7.2)
|
|
175
|
-
# ==============================================================================
|
|
176
|
-
|
|
177
|
-
@dataclass
|
|
178
|
-
class FLCParams:
|
|
179
|
-
"""Optimized FLC model parameters."""
|
|
180
|
-
# Base FLC₀ parameters
|
|
181
|
-
A: float = 0.2383
|
|
182
|
-
alpha: float = 0.150 # (1 - r_th) exponent
|
|
183
|
-
beta_fd: float = -0.166 # f_d exponent
|
|
184
|
-
gamma_E: float = 0.227 # E_bond exponent
|
|
185
|
-
|
|
186
|
-
# Free volume consumption coefficients
|
|
187
|
-
k_ss: float = -0.098 # Solid solution
|
|
188
|
-
k_ppt: float = 0.345 # Precipitate/martensite
|
|
189
|
-
k_wh: float = 0.067 # Work hardening
|
|
190
|
-
k_HP: float = 0.050 # Hall-Petch (grain refinement)
|
|
191
|
-
|
|
192
|
-
# V-shape parameters
|
|
193
|
-
k_neg: float = 0.597 # Deep draw bonus
|
|
194
|
-
k_pos: float = 0.235 # Biaxial penalty
|
|
195
|
-
w_neg: float = 0.313 # Deep draw width
|
|
196
|
-
w_pos: float = 0.450 # Biaxial width
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
class FLCPredictor:
|
|
200
|
-
"""
|
|
201
|
-
δ-Theory FLC Predictor (v7.2)
|
|
202
|
-
|
|
203
|
-
Predicts Forming Limit Curve based on:
|
|
204
|
-
- Crystal structure (r_th, n_slip)
|
|
205
|
-
- d-electron directionality (f_d)
|
|
206
|
-
- Bond energy (E_bond)
|
|
207
|
-
- Free volume consumption (strengthening mechanisms)
|
|
208
|
-
- Multiaxial stress state (τ/σ, R)
|
|
209
|
-
"""
|
|
210
|
-
|
|
211
|
-
def __init__(self, params: Optional[FLCParams] = None):
|
|
212
|
-
self.params = params or FLCParams()
|
|
213
|
-
self._materials = FLC_MATERIALS.copy()
|
|
214
|
-
|
|
215
|
-
def add_material(self, mat: FLCMaterial) -> None:
|
|
216
|
-
"""Add custom material to database."""
|
|
217
|
-
self._materials[mat.name] = mat
|
|
218
|
-
|
|
219
|
-
def get_material(self, name: str) -> FLCMaterial:
|
|
220
|
-
"""Get material by name."""
|
|
221
|
-
if name not in self._materials:
|
|
222
|
-
raise ValueError(f"Material '{name}' not found. "
|
|
223
|
-
f"Available: {list(self._materials.keys())}")
|
|
224
|
-
return self._materials[name]
|
|
225
|
-
|
|
226
|
-
def free_volume_consumption(self, mat: FLCMaterial) -> Tuple[float, Dict[str, float]]:
|
|
227
|
-
"""
|
|
228
|
-
Calculate free volume consumption from strengthening mechanisms.
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
(remaining_ratio, breakdown_dict)
|
|
232
|
-
"""
|
|
233
|
-
p = self.params
|
|
234
|
-
|
|
235
|
-
# Solid solution
|
|
236
|
-
eta_ss = p.k_ss * mat.C_ss
|
|
237
|
-
|
|
238
|
-
# Precipitate/martensite
|
|
239
|
-
eta_ppt = p.k_ppt * mat.f_ppt
|
|
240
|
-
|
|
241
|
-
# Work hardening (dislocation density)
|
|
242
|
-
rho_ref = 1e12
|
|
243
|
-
eta_wh = p.k_wh * np.log10(mat.rho_d / rho_ref) if mat.rho_d > rho_ref else 0.0
|
|
244
|
-
|
|
245
|
-
# Hall-Petch (grain refinement)
|
|
246
|
-
d_ref = 50e-6
|
|
247
|
-
eta_HP = p.k_HP * (np.sqrt(d_ref / mat.d_grain) - 1) if mat.d_grain < d_ref else 0.0
|
|
248
|
-
|
|
249
|
-
eta_total = eta_ss + eta_ppt + eta_wh + eta_HP
|
|
250
|
-
remaining = max(0.1, 1 - eta_total)
|
|
251
|
-
|
|
252
|
-
breakdown = {
|
|
253
|
-
'eta_ss': eta_ss,
|
|
254
|
-
'eta_ppt': eta_ppt,
|
|
255
|
-
'eta_wh': eta_wh,
|
|
256
|
-
'eta_HP': eta_HP,
|
|
257
|
-
'eta_total': eta_total,
|
|
258
|
-
'remaining': remaining,
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return remaining, breakdown
|
|
262
|
-
|
|
263
|
-
def flc0_pure(self, mat: FLCMaterial) -> float:
|
|
264
|
-
"""
|
|
265
|
-
Calculate pure metal FLC₀ (β=0).
|
|
266
|
-
|
|
267
|
-
FLC₀_pure = A × (1-r_th)^α × f_d^β × E_bond^γ
|
|
268
|
-
"""
|
|
269
|
-
p = self.params
|
|
270
|
-
return (p.A
|
|
271
|
-
* ((1 - mat.r_th) ** p.alpha)
|
|
272
|
-
* (mat.f_d ** p.beta_fd)
|
|
273
|
-
* (mat.E_bond ** p.gamma_E))
|
|
274
|
-
|
|
275
|
-
def shape_factor(self, beta: float, mat: FLCMaterial) -> float:
|
|
276
|
-
"""
|
|
277
|
-
Calculate V-shape factor h(β, R, τ/σ).
|
|
278
|
-
|
|
279
|
-
β < 0: Deep draw → R-dependent bonus
|
|
280
|
-
β > 0: Biaxial → τ/σ-dependent penalty
|
|
281
|
-
"""
|
|
282
|
-
p = self.params
|
|
283
|
-
|
|
284
|
-
if beta <= 0:
|
|
285
|
-
# Deep draw: compression component
|
|
286
|
-
# R = 1: symmetric → bonus
|
|
287
|
-
# R < 1 (Mg): compression weak → reduced bonus
|
|
288
|
-
bonus = p.k_neg * mat.R_comp * np.exp(-((beta + 0.5) / p.w_neg)**2)
|
|
289
|
-
h = 1 + bonus
|
|
290
|
-
else:
|
|
291
|
-
# Biaxial: shear component (thickness reduction)
|
|
292
|
-
# τ/σ = 0.565: normal → base penalty
|
|
293
|
-
# τ/σ < 0.565 (Mg): shear weak → increased penalty
|
|
294
|
-
penalty = p.k_pos * (0.565 / mat.tau_sigma) * (1 - np.exp(-((beta - 0) / p.w_pos)**2))
|
|
295
|
-
h = 1 - penalty
|
|
296
|
-
|
|
297
|
-
return h
|
|
298
|
-
|
|
299
|
-
def predict(self,
|
|
300
|
-
beta: float,
|
|
301
|
-
material: Union[str, FLCMaterial],
|
|
302
|
-
include_breakdown: bool = False) -> Union[float, Tuple[float, Dict]]:
|
|
303
|
-
"""
|
|
304
|
-
Predict FLC (major strain limit) at given β.
|
|
305
|
-
|
|
306
|
-
Args:
|
|
307
|
-
beta: Strain ratio ε₂/ε₁ (-0.5 to 1.0)
|
|
308
|
-
material: Material name or FLCMaterial object
|
|
309
|
-
include_breakdown: If True, return (Em, breakdown_dict)
|
|
310
|
-
|
|
311
|
-
Returns:
|
|
312
|
-
Em: Major strain limit at β
|
|
313
|
-
breakdown: (optional) Dict with intermediate values
|
|
314
|
-
"""
|
|
315
|
-
if isinstance(material, str):
|
|
316
|
-
mat = self.get_material(material)
|
|
317
|
-
else:
|
|
318
|
-
mat = material
|
|
319
|
-
|
|
320
|
-
# Base FLC₀ for pure metal
|
|
321
|
-
FLC0_pure = self.flc0_pure(mat)
|
|
322
|
-
|
|
323
|
-
# Free volume consumption
|
|
324
|
-
fv_ratio, fv_breakdown = self.free_volume_consumption(mat)
|
|
325
|
-
FLC0 = FLC0_pure * fv_ratio
|
|
326
|
-
|
|
327
|
-
# Shape factor
|
|
328
|
-
h = self.shape_factor(beta, mat)
|
|
329
|
-
|
|
330
|
-
# Final FLC
|
|
331
|
-
Em = FLC0 * h
|
|
332
|
-
|
|
333
|
-
if include_breakdown:
|
|
334
|
-
breakdown = {
|
|
335
|
-
'FLC0_pure': FLC0_pure,
|
|
336
|
-
'fv_ratio': fv_ratio,
|
|
337
|
-
'FLC0': FLC0,
|
|
338
|
-
'h': h,
|
|
339
|
-
'Em': Em,
|
|
340
|
-
**fv_breakdown
|
|
341
|
-
}
|
|
342
|
-
return Em, breakdown
|
|
343
|
-
|
|
344
|
-
return Em
|
|
345
|
-
|
|
346
|
-
def predict_curve(self,
|
|
347
|
-
material: Union[str, FLCMaterial],
|
|
348
|
-
beta_range: Optional[np.ndarray] = None,
|
|
349
|
-
n_points: int = 50) -> Tuple[np.ndarray, np.ndarray]:
|
|
350
|
-
"""
|
|
351
|
-
Predict full FLC curve.
|
|
352
|
-
|
|
353
|
-
Returns:
|
|
354
|
-
(beta_array, Em_array)
|
|
355
|
-
"""
|
|
356
|
-
if beta_range is None:
|
|
357
|
-
beta_range = np.linspace(-0.5, 1.0, n_points)
|
|
358
|
-
|
|
359
|
-
Em_values = np.array([self.predict(b, material) for b in beta_range])
|
|
360
|
-
return beta_range, Em_values
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
# ==============================================================================
|
|
364
|
-
# Forming-Fatigue Integrator (v8.0)
|
|
365
|
-
# ==============================================================================
|
|
366
|
-
|
|
367
|
-
@dataclass
|
|
368
|
-
class FormingState:
|
|
369
|
-
"""State of formed material at a point."""
|
|
370
|
-
eta_forming: float # Free volume consumption from forming
|
|
371
|
-
r_th_eff: float # Effective fatigue threshold
|
|
372
|
-
structure: str # Crystal structure
|
|
373
|
-
|
|
374
|
-
# Optional: position info
|
|
375
|
-
x: Optional[float] = None
|
|
376
|
-
y: Optional[float] = None
|
|
377
|
-
z: Optional[float] = None
|
|
378
|
-
|
|
379
|
-
@property
|
|
380
|
-
def fatigue_limit_reduction(self) -> float:
|
|
381
|
-
"""Fatigue limit reduction ratio."""
|
|
382
|
-
r_th_virgin = R_TH_VIRGIN[self.structure]
|
|
383
|
-
return 1 - (self.r_th_eff / r_th_virgin)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
class FormingFatigueIntegrator:
|
|
387
|
-
"""
|
|
388
|
-
δ-Theory Forming-Fatigue Integration (v8.0)
|
|
389
|
-
|
|
390
|
-
Predicts how forming history affects fatigue life:
|
|
391
|
-
- η_forming: Free volume consumed during forming
|
|
392
|
-
- r_th_eff: Effective fatigue threshold after forming
|
|
393
|
-
- N/N₀: Fatigue life ratio vs virgin material
|
|
394
|
-
"""
|
|
395
|
-
|
|
396
|
-
def __init__(self, kappa: float = 1.0):
|
|
397
|
-
"""
|
|
398
|
-
Args:
|
|
399
|
-
kappa: Forming-fatigue coupling exponent
|
|
400
|
-
κ > 1: Forming damage strongly affects fatigue
|
|
401
|
-
κ < 1: Forming damage mildly affects fatigue
|
|
402
|
-
"""
|
|
403
|
-
self.kappa = kappa
|
|
404
|
-
|
|
405
|
-
def effective_r_th(self,
|
|
406
|
-
eta_forming: float,
|
|
407
|
-
structure: Literal['BCC', 'FCC', 'HCP']) -> float:
|
|
408
|
-
"""
|
|
409
|
-
Calculate effective fatigue threshold after forming.
|
|
410
|
-
|
|
411
|
-
r_th_eff = r_th_virgin × (1 - η_forming)^κ
|
|
412
|
-
|
|
413
|
-
Args:
|
|
414
|
-
eta_forming: Free volume consumption (0 to 1)
|
|
415
|
-
structure: Crystal structure
|
|
416
|
-
|
|
417
|
-
Returns:
|
|
418
|
-
r_th_eff: Effective fatigue threshold
|
|
419
|
-
"""
|
|
420
|
-
r_th_v = R_TH_VIRGIN[structure]
|
|
421
|
-
remaining = max(0.01, 1 - eta_forming)
|
|
422
|
-
return r_th_v * (remaining ** self.kappa)
|
|
423
|
-
|
|
424
|
-
def critical_eta(self,
|
|
425
|
-
r_applied: float,
|
|
426
|
-
structure: Literal['BCC', 'FCC', 'HCP']) -> float:
|
|
427
|
-
"""
|
|
428
|
-
Calculate critical forming consumption.
|
|
429
|
-
|
|
430
|
-
Beyond this η, virgin-safe stress becomes finite-life.
|
|
431
|
-
|
|
432
|
-
Args:
|
|
433
|
-
r_applied: Applied stress ratio σ_a/σ_y
|
|
434
|
-
structure: Crystal structure
|
|
435
|
-
|
|
436
|
-
Returns:
|
|
437
|
-
η_critical: Critical forming consumption
|
|
438
|
-
"""
|
|
439
|
-
r_th_v = R_TH_VIRGIN[structure]
|
|
440
|
-
|
|
441
|
-
if r_applied >= r_th_v:
|
|
442
|
-
return 0.0 # Already finite life
|
|
443
|
-
|
|
444
|
-
# r_th_eff = r_applied at critical point
|
|
445
|
-
# r_th_v × (1 - η)^κ = r_applied
|
|
446
|
-
# (1 - η)^κ = r_applied / r_th_v
|
|
447
|
-
# 1 - η = (r_applied / r_th_v)^(1/κ)
|
|
448
|
-
# η = 1 - (r_applied / r_th_v)^(1/κ)
|
|
449
|
-
|
|
450
|
-
return 1 - (r_applied / r_th_v) ** (1 / self.kappa)
|
|
451
|
-
|
|
452
|
-
def fatigue_life_ratio(self,
|
|
453
|
-
r_applied: float,
|
|
454
|
-
eta_forming: float,
|
|
455
|
-
structure: Literal['BCC', 'FCC', 'HCP'],
|
|
456
|
-
n_exp: float = 15.0) -> float:
|
|
457
|
-
"""
|
|
458
|
-
Calculate fatigue life ratio N/N₀.
|
|
459
|
-
|
|
460
|
-
Args:
|
|
461
|
-
r_applied: Applied stress ratio σ_a/σ_y
|
|
462
|
-
eta_forming: Free volume consumption from forming
|
|
463
|
-
structure: Crystal structure
|
|
464
|
-
n_exp: Basquin exponent
|
|
465
|
-
|
|
466
|
-
Returns:
|
|
467
|
-
N/N₀: Fatigue life ratio (∞ if below threshold)
|
|
468
|
-
"""
|
|
469
|
-
r_th_v = R_TH_VIRGIN[structure]
|
|
470
|
-
r_th_eff = self.effective_r_th(eta_forming, structure)
|
|
471
|
-
|
|
472
|
-
# Case 1: Below effective threshold → infinite life
|
|
473
|
-
if r_applied <= r_th_eff:
|
|
474
|
-
return np.inf
|
|
475
|
-
|
|
476
|
-
# Case 2: Virgin was also finite life
|
|
477
|
-
if r_applied > r_th_v:
|
|
478
|
-
term_virgin = (r_applied - r_th_v) / (1 - r_th_v)
|
|
479
|
-
term_formed = (r_applied - r_th_eff) / (1 - r_th_eff)
|
|
480
|
-
return (term_formed / term_virgin) ** (-n_exp)
|
|
481
|
-
|
|
482
|
-
# Case 3: Virgin was infinite, now finite
|
|
483
|
-
# Return absolute cycles instead of ratio
|
|
484
|
-
return 0.0 # Indicates transition from infinite to finite
|
|
485
|
-
|
|
486
|
-
def is_safe(self,
|
|
487
|
-
r_applied: float,
|
|
488
|
-
eta_forming: float,
|
|
489
|
-
structure: Literal['BCC', 'FCC', 'HCP']) -> bool:
|
|
490
|
-
"""Check if formed material is safe (below fatigue limit)."""
|
|
491
|
-
r_th_eff = self.effective_r_th(eta_forming, structure)
|
|
492
|
-
return r_applied <= r_th_eff
|
|
493
|
-
|
|
494
|
-
def analyze_forming_steps(self,
|
|
495
|
-
eta_steps: List[float],
|
|
496
|
-
r_applied: float,
|
|
497
|
-
structure: Literal['BCC', 'FCC', 'HCP']) -> List[FormingState]:
|
|
498
|
-
"""
|
|
499
|
-
Analyze forming process step by step.
|
|
500
|
-
|
|
501
|
-
Args:
|
|
502
|
-
eta_steps: Cumulative η at each step
|
|
503
|
-
r_applied: Applied stress during use
|
|
504
|
-
structure: Crystal structure
|
|
505
|
-
|
|
506
|
-
Returns:
|
|
507
|
-
List of FormingState for each step
|
|
508
|
-
"""
|
|
509
|
-
states = []
|
|
510
|
-
for i, eta in enumerate(eta_steps):
|
|
511
|
-
r_th_eff = self.effective_r_th(eta, structure)
|
|
512
|
-
state = FormingState(
|
|
513
|
-
eta_forming=eta,
|
|
514
|
-
r_th_eff=r_th_eff,
|
|
515
|
-
structure=structure
|
|
516
|
-
)
|
|
517
|
-
states.append(state)
|
|
518
|
-
|
|
519
|
-
return states
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
# ==============================================================================
|
|
523
|
-
# Combined Analysis
|
|
524
|
-
# ==============================================================================
|
|
525
|
-
|
|
526
|
-
class DeltaFormingAnalyzer:
|
|
527
|
-
"""
|
|
528
|
-
Combined FLC + Forming-Fatigue Analysis.
|
|
529
|
-
|
|
530
|
-
Workflow:
|
|
531
|
-
1. Predict FLC for material
|
|
532
|
-
2. Assess forming risk (Λ = ε_actual / FLC)
|
|
533
|
-
3. Calculate η consumption at each point
|
|
534
|
-
4. Predict post-forming fatigue life
|
|
535
|
-
"""
|
|
536
|
-
|
|
537
|
-
def __init__(self,
|
|
538
|
-
flc_params: Optional[FLCParams] = None,
|
|
539
|
-
kappa: float = 1.0):
|
|
540
|
-
self.flc = FLCPredictor(flc_params)
|
|
541
|
-
self.fatigue = FormingFatigueIntegrator(kappa)
|
|
542
|
-
|
|
543
|
-
def forming_lambda(self,
|
|
544
|
-
epsilon_major: float,
|
|
545
|
-
beta: float,
|
|
546
|
-
material: Union[str, FLCMaterial]) -> float:
|
|
547
|
-
"""
|
|
548
|
-
Calculate forming severity parameter Λ.
|
|
549
|
-
|
|
550
|
-
Λ = ε_actual / FLC
|
|
551
|
-
Λ < 1: Safe
|
|
552
|
-
Λ = 1: Critical
|
|
553
|
-
Λ > 1: Failure
|
|
554
|
-
"""
|
|
555
|
-
flc = self.flc.predict(beta, material)
|
|
556
|
-
return epsilon_major / flc
|
|
557
|
-
|
|
558
|
-
def eta_from_lambda(self,
|
|
559
|
-
lambda_val: float,
|
|
560
|
-
max_eta: float = 0.95) -> float:
|
|
561
|
-
"""
|
|
562
|
-
Estimate η from Λ.
|
|
563
|
-
|
|
564
|
-
Simple model: η ≈ Λ (up to max_eta)
|
|
565
|
-
"""
|
|
566
|
-
return min(lambda_val, max_eta)
|
|
567
|
-
|
|
568
|
-
def full_analysis(self,
|
|
569
|
-
material: Union[str, FLCMaterial],
|
|
570
|
-
epsilon_major: float,
|
|
571
|
-
beta: float,
|
|
572
|
-
r_applied: float) -> Dict:
|
|
573
|
-
"""
|
|
574
|
-
Complete forming + fatigue analysis.
|
|
575
|
-
|
|
576
|
-
Returns dict with all relevant parameters.
|
|
577
|
-
"""
|
|
578
|
-
if isinstance(material, str):
|
|
579
|
-
mat = self.flc.get_material(material)
|
|
580
|
-
else:
|
|
581
|
-
mat = material
|
|
582
|
-
|
|
583
|
-
# FLC prediction
|
|
584
|
-
flc, flc_breakdown = self.flc.predict(beta, mat, include_breakdown=True)
|
|
585
|
-
|
|
586
|
-
# Forming severity
|
|
587
|
-
lambda_val = epsilon_major / flc
|
|
588
|
-
|
|
589
|
-
# Estimate η
|
|
590
|
-
eta = self.eta_from_lambda(lambda_val)
|
|
591
|
-
|
|
592
|
-
# Effective fatigue threshold
|
|
593
|
-
r_th_eff = self.fatigue.effective_r_th(eta, mat.structure)
|
|
594
|
-
|
|
595
|
-
# Fatigue life ratio
|
|
596
|
-
N_ratio = self.fatigue.fatigue_life_ratio(r_applied, eta, mat.structure)
|
|
597
|
-
|
|
598
|
-
# Safety assessment
|
|
599
|
-
is_forming_safe = lambda_val < 1.0
|
|
600
|
-
is_fatigue_safe = self.fatigue.is_safe(r_applied, eta, mat.structure)
|
|
601
|
-
|
|
602
|
-
return {
|
|
603
|
-
'material': mat.name,
|
|
604
|
-
'structure': mat.structure,
|
|
605
|
-
# Forming
|
|
606
|
-
'FLC': flc,
|
|
607
|
-
'epsilon_major': epsilon_major,
|
|
608
|
-
'beta': beta,
|
|
609
|
-
'Lambda': lambda_val,
|
|
610
|
-
'is_forming_safe': is_forming_safe,
|
|
611
|
-
# Free volume
|
|
612
|
-
'eta_forming': eta,
|
|
613
|
-
'fv_remaining': 1 - eta,
|
|
614
|
-
**flc_breakdown,
|
|
615
|
-
# Fatigue
|
|
616
|
-
'r_th_virgin': mat.r_th,
|
|
617
|
-
'r_th_eff': r_th_eff,
|
|
618
|
-
'r_applied': r_applied,
|
|
619
|
-
'N_ratio': N_ratio,
|
|
620
|
-
'is_fatigue_safe': is_fatigue_safe,
|
|
621
|
-
# Overall
|
|
622
|
-
'overall_safe': is_forming_safe and is_fatigue_safe,
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
# ==============================================================================
|
|
627
|
-
# Convenience functions
|
|
628
|
-
# ==============================================================================
|
|
629
|
-
|
|
630
|
-
def predict_flc(material: str, beta: float = 0.0) -> float:
|
|
631
|
-
"""Quick FLC prediction."""
|
|
632
|
-
return FLCPredictor().predict(beta, material)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
def effective_fatigue_threshold(eta: float, structure: str) -> float:
|
|
636
|
-
"""Quick effective r_th calculation."""
|
|
637
|
-
return FormingFatigueIntegrator().effective_r_th(eta, structure)
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
def critical_forming_consumption(r_applied: float, structure: str) -> float:
|
|
641
|
-
"""Quick critical η calculation."""
|
|
642
|
-
return FormingFatigueIntegrator().critical_eta(r_applied, structure)
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
# ==============================================================================
|
|
646
|
-
# Demo / Test
|
|
647
|
-
# ==============================================================================
|
|
648
|
-
|
|
649
|
-
def demo():
|
|
650
|
-
"""Demonstration of v7.2 + v8.0 capabilities."""
|
|
651
|
-
|
|
652
|
-
print("="*70)
|
|
653
|
-
print("δ-Theory v7.2 + v8.0: FLC & Forming-Fatigue Integration")
|
|
654
|
-
print("="*70)
|
|
655
|
-
|
|
656
|
-
# FLC Prediction
|
|
657
|
-
print("\n[1] FLC Prediction (v7.2)")
|
|
658
|
-
print("-"*40)
|
|
659
|
-
|
|
660
|
-
flc = FLCPredictor()
|
|
661
|
-
|
|
662
|
-
materials = ['SPCC', 'DP590', 'Al', 'SUS304', 'Ti', 'Mg_AZ31']
|
|
663
|
-
betas = [-0.5, 0.0, 1.0]
|
|
664
|
-
|
|
665
|
-
print(f"{'Material':10} {'β=-0.5':>8} {'β=0':>8} {'β=1':>8}")
|
|
666
|
-
print("-"*40)
|
|
667
|
-
|
|
668
|
-
for mat_name in materials:
|
|
669
|
-
Em_values = [flc.predict(b, mat_name) for b in betas]
|
|
670
|
-
print(f"{mat_name:10} {Em_values[0]:>8.3f} {Em_values[1]:>8.3f} {Em_values[2]:>8.3f}")
|
|
671
|
-
|
|
672
|
-
# Free Volume Breakdown
|
|
673
|
-
print("\n[2] Free Volume Consumption Breakdown")
|
|
674
|
-
print("-"*40)
|
|
675
|
-
|
|
676
|
-
for mat_name in ['SPCC', 'DP590']:
|
|
677
|
-
mat = flc.get_material(mat_name)
|
|
678
|
-
fv_ratio, breakdown = flc.free_volume_consumption(mat)
|
|
679
|
-
print(f"\n{mat_name}:")
|
|
680
|
-
print(f" η_ss = {breakdown['eta_ss']:.3f} (solid solution)")
|
|
681
|
-
print(f" η_ppt = {breakdown['eta_ppt']:.3f} (precipitate)")
|
|
682
|
-
print(f" η_wh = {breakdown['eta_wh']:.3f} (work hardening)")
|
|
683
|
-
print(f" η_HP = {breakdown['eta_HP']:.3f} (grain refinement)")
|
|
684
|
-
print(f" FV remaining = {fv_ratio:.3f}")
|
|
685
|
-
|
|
686
|
-
# Forming-Fatigue Integration
|
|
687
|
-
print("\n[3] Forming-Fatigue Integration (v8.0)")
|
|
688
|
-
print("-"*40)
|
|
689
|
-
|
|
690
|
-
integrator = FormingFatigueIntegrator()
|
|
691
|
-
|
|
692
|
-
# Critical η for various stress levels
|
|
693
|
-
print("\nCritical η for BCC steel (r_th_virgin = 0.65):")
|
|
694
|
-
for r in [0.30, 0.40, 0.50, 0.55, 0.60]:
|
|
695
|
-
eta_crit = integrator.critical_eta(r, 'BCC')
|
|
696
|
-
print(f" r = {r:.2f} → η_critical = {eta_crit*100:.1f}%")
|
|
697
|
-
|
|
698
|
-
# Nidec part example
|
|
699
|
-
print("\n[4] Nidec Part Example (SECD-E16)")
|
|
700
|
-
print("-"*40)
|
|
701
|
-
|
|
702
|
-
analyzer = DeltaFormingAnalyzer()
|
|
703
|
-
|
|
704
|
-
result = analyzer.full_analysis(
|
|
705
|
-
material='SECD-E16',
|
|
706
|
-
epsilon_major=0.25, # 25% strain at corner
|
|
707
|
-
beta=0.0, # Plane strain
|
|
708
|
-
r_applied=0.50 # 50% of yield stress during use
|
|
709
|
-
)
|
|
710
|
-
|
|
711
|
-
print(f"Material: {result['material']} ({result['structure']})")
|
|
712
|
-
print(f"\nForming:")
|
|
713
|
-
print(f" ε_major = {result['epsilon_major']:.2f}")
|
|
714
|
-
print(f" FLC = {result['FLC']:.3f}")
|
|
715
|
-
print(f" Λ = {result['Lambda']:.3f}")
|
|
716
|
-
print(f" Safe? = {result['is_forming_safe']}")
|
|
717
|
-
print(f"\nFatigue:")
|
|
718
|
-
print(f" η_forming = {result['eta_forming']:.3f}")
|
|
719
|
-
print(f" r_th_virgin = {result['r_th_virgin']:.3f}")
|
|
720
|
-
print(f" r_th_eff = {result['r_th_eff']:.3f}")
|
|
721
|
-
print(f" r_applied = {result['r_applied']:.3f}")
|
|
722
|
-
print(f" Safe? = {result['is_fatigue_safe']}")
|
|
723
|
-
print(f"\nOverall: {'✓ SAFE' if result['overall_safe'] else '✗ UNSAFE'}")
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if __name__ == '__main__':
|
|
727
|
-
demo()
|