delta-theory 8.1.2__py3-none-any.whl → 8.2.1__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 +768 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.1.dist-info}/METADATA +150 -124
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.1.dist-info}/RECORD +9 -9
- core/unified_flc_v7.py +0 -727
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.1.dist-info}/WHEEL +0 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.1.dist-info}/entry_points.txt +0 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.1.dist-info}/licenses/LICENSE +0 -0
- {delta_theory-8.1.2.dist-info → delta_theory-8.2.1.dist-info}/top_level.txt +0 -0
core/unified_flc_v8_1.py
ADDED
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""δ-Theory Unified FLC v8.1 - Integrated with v6.9
|
|
3
|
+
|
|
4
|
+
=============================================================================
|
|
5
|
+
v8.0 → v8.1: Integration with unified_yield_fatigue_v6_9
|
|
6
|
+
=============================================================================
|
|
7
|
+
|
|
8
|
+
【新機能】
|
|
9
|
+
- v6.9 から材料パラメータを自動取得
|
|
10
|
+
- FLCMaterial.from_v69() で簡単に材料作成
|
|
11
|
+
- FLC₀ 1点校正で全モード予測
|
|
12
|
+
- v6.9のMaterialクラスから直接変換
|
|
13
|
+
|
|
14
|
+
【使い方】
|
|
15
|
+
# v6.9 材料から直接 FLC 予測
|
|
16
|
+
flc = FLCPredictor()
|
|
17
|
+
flc.add_from_v69('Fe', flc0=0.225) # SPCC相当
|
|
18
|
+
eps1 = flc.predict('Fe', 'Plane Strain')
|
|
19
|
+
|
|
20
|
+
# カスタム材料
|
|
21
|
+
flc.add_from_v69(
|
|
22
|
+
name='MyAlloy',
|
|
23
|
+
base_element='Fe',
|
|
24
|
+
structure='BCC',
|
|
25
|
+
flc0=0.28,
|
|
26
|
+
T_twin=1.0,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# v6.9のMaterialクラスから直接
|
|
30
|
+
# (v6.9がimport可能な場合)
|
|
31
|
+
from unified_yield_fatigue_v6_9 import MATERIALS
|
|
32
|
+
flc.add_from_v69_material(MATERIALS['Fe'], flc0=0.225, name='SPCC')
|
|
33
|
+
|
|
34
|
+
Author: δ-Theory Team (Masamichi Iizumi & Tamaki)
|
|
35
|
+
Version: 8.1.0
|
|
36
|
+
Date: 2025-02
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
import warnings
|
|
42
|
+
from dataclasses import dataclass
|
|
43
|
+
from typing import Dict, List, Optional, Tuple, Union
|
|
44
|
+
import numpy as np
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ==============================================================================
|
|
48
|
+
# Try to import v6.9b
|
|
49
|
+
# ==============================================================================
|
|
50
|
+
|
|
51
|
+
V69_AVAILABLE = False
|
|
52
|
+
V69_MATERIALS = {}
|
|
53
|
+
V69_Material = None
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
from unified_yield_fatigue_v6_9 import (
|
|
57
|
+
tau_over_sigma as v69_tau_over_sigma,
|
|
58
|
+
sigma_c_over_sigma_t as v69_sigma_c_over_sigma_t,
|
|
59
|
+
sigma_base_delta,
|
|
60
|
+
calc_sigma_y,
|
|
61
|
+
Material as V69_Material,
|
|
62
|
+
MATERIALS as V69_MATERIALS,
|
|
63
|
+
T_TWIN as V69_T_TWIN,
|
|
64
|
+
R_COMP as V69_R_COMP,
|
|
65
|
+
C_CLASS_DEFAULT,
|
|
66
|
+
DEFAULT_BCC_W110,
|
|
67
|
+
)
|
|
68
|
+
V69_AVAILABLE = True
|
|
69
|
+
except ImportError:
|
|
70
|
+
try:
|
|
71
|
+
# Try relative import (as package)
|
|
72
|
+
from .unified_yield_fatigue_v6_9 import (
|
|
73
|
+
tau_over_sigma as v69_tau_over_sigma,
|
|
74
|
+
sigma_c_over_sigma_t as v69_sigma_c_over_sigma_t,
|
|
75
|
+
sigma_base_delta,
|
|
76
|
+
calc_sigma_y,
|
|
77
|
+
Material as V69_Material,
|
|
78
|
+
MATERIALS as V69_MATERIALS,
|
|
79
|
+
T_TWIN as V69_T_TWIN,
|
|
80
|
+
R_COMP as V69_R_COMP,
|
|
81
|
+
C_CLASS_DEFAULT,
|
|
82
|
+
DEFAULT_BCC_W110,
|
|
83
|
+
)
|
|
84
|
+
V69_AVAILABLE = True
|
|
85
|
+
except ImportError:
|
|
86
|
+
warnings.warn(
|
|
87
|
+
"unified_yield_fatigue_v6_9 not found. "
|
|
88
|
+
"Using built-in parameters. "
|
|
89
|
+
"For full functionality, ensure v6.9 is in the same directory."
|
|
90
|
+
)
|
|
91
|
+
V69_AVAILABLE = False
|
|
92
|
+
# Fallback defaults
|
|
93
|
+
v69_tau_over_sigma = None
|
|
94
|
+
v69_sigma_c_over_sigma_t = None
|
|
95
|
+
V69_MATERIALS = {}
|
|
96
|
+
C_CLASS_DEFAULT = 1.415
|
|
97
|
+
DEFAULT_BCC_W110 = 0.0
|
|
98
|
+
V69_T_TWIN = {}
|
|
99
|
+
V69_R_COMP = {}
|
|
100
|
+
|
|
101
|
+
# ==============================================================================
|
|
102
|
+
# Built-in Parameters (Fallback when v6.9 not available)
|
|
103
|
+
# ==============================================================================
|
|
104
|
+
|
|
105
|
+
# τ/σ ratios from δ-theory
|
|
106
|
+
BUILTIN_TAU_SIGMA = {
|
|
107
|
+
# Pure metals
|
|
108
|
+
'Fe': 0.565, 'Cu': 0.565, 'Al': 0.565, 'Ni': 0.565,
|
|
109
|
+
'Ti': 0.546, 'Mg': 0.327, 'Zn': 0.480,
|
|
110
|
+
# Crystal structures (default)
|
|
111
|
+
'BCC': 0.565, 'FCC': 0.565, 'HCP': 0.500,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# R_comp (σ_c/σ_t) ratios
|
|
115
|
+
BUILTIN_R_COMP = {
|
|
116
|
+
'Fe': 1.00, 'Cu': 1.00, 'Al': 1.00, 'Ni': 1.00,
|
|
117
|
+
'Ti': 1.00, 'Mg': 0.60, 'Zn': 1.20,
|
|
118
|
+
'BCC': 1.00, 'FCC': 1.00, 'HCP': 0.80,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Element to structure mapping
|
|
122
|
+
ELEMENT_STRUCTURE = {
|
|
123
|
+
'Fe': 'BCC', 'Cr': 'BCC', 'Mo': 'BCC', 'W': 'BCC', 'V': 'BCC',
|
|
124
|
+
'Cu': 'FCC', 'Al': 'FCC', 'Ni': 'FCC', 'Ag': 'FCC', 'Au': 'FCC',
|
|
125
|
+
'Ti': 'HCP', 'Mg': 'HCP', 'Zn': 'HCP', 'Zr': 'HCP',
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_tau_sigma(element_or_structure: str, T_twin: float = 1.0) -> float:
|
|
130
|
+
"""
|
|
131
|
+
Get τ/σ ratio.
|
|
132
|
+
|
|
133
|
+
Uses v6.9b if available for BCC/FCC, built-in interpolation for HCP.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
element_or_structure: Element name ('Fe', 'Cu') or structure ('BCC', 'FCC')
|
|
137
|
+
T_twin: Twinning factor for HCP (0.0=twin-dominated, 1.0=slip-dominated)
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
τ/σ ratio
|
|
141
|
+
|
|
142
|
+
Note:
|
|
143
|
+
For HCP, we always use built-in interpolation because:
|
|
144
|
+
- v6.9's tau_over_sigma multiplies by T_twin directly (→ 0 when T_twin=0)
|
|
145
|
+
- FLC needs T_twin as interpolation parameter between slip/twin modes
|
|
146
|
+
- T_twin=0.0 → Mg-like twin-dominated (τ/σ ≈ 0.327)
|
|
147
|
+
- T_twin=1.0 → slip-dominated (τ/σ ≈ 0.565)
|
|
148
|
+
"""
|
|
149
|
+
structure = ELEMENT_STRUCTURE.get(element_or_structure, element_or_structure)
|
|
150
|
+
|
|
151
|
+
# HCP: Always use built-in interpolation (v6.9 T_twin semantics differ)
|
|
152
|
+
if structure == 'HCP':
|
|
153
|
+
tau_slip = 0.565 # Normal slip-dominated
|
|
154
|
+
if element_or_structure == 'Mg':
|
|
155
|
+
tau_twin = 0.327 # Mg twin-dominated (calibrated)
|
|
156
|
+
elif element_or_structure == 'Ti':
|
|
157
|
+
tau_twin = 0.546 # Ti (mostly slip even with twinning)
|
|
158
|
+
elif element_or_structure == 'Zn':
|
|
159
|
+
tau_twin = 0.480 # Zn
|
|
160
|
+
else:
|
|
161
|
+
tau_twin = 0.50 # Generic HCP
|
|
162
|
+
|
|
163
|
+
# T_twin=1.0 → slip-dominated (0.565)
|
|
164
|
+
# T_twin=0.0 → twin-dominated (element-specific)
|
|
165
|
+
return tau_slip * T_twin + tau_twin * (1 - T_twin)
|
|
166
|
+
|
|
167
|
+
# BCC/FCC: Use v6.9 if available
|
|
168
|
+
if V69_AVAILABLE and element_or_structure in V69_MATERIALS:
|
|
169
|
+
mat = V69_MATERIALS[element_or_structure]
|
|
170
|
+
return v69_tau_over_sigma(mat, C_CLASS_DEFAULT, DEFAULT_BCC_W110)
|
|
171
|
+
|
|
172
|
+
# Fallback to built-in
|
|
173
|
+
if element_or_structure in BUILTIN_TAU_SIGMA:
|
|
174
|
+
return BUILTIN_TAU_SIGMA[element_or_structure]
|
|
175
|
+
else:
|
|
176
|
+
return BUILTIN_TAU_SIGMA.get(structure, 0.565)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def get_R_comp(element_or_structure: str, T_twin: float = 1.0) -> float:
|
|
180
|
+
"""
|
|
181
|
+
Get R_comp (σ_c/σ_t) ratio.
|
|
182
|
+
|
|
183
|
+
Uses v6.9b if available for BCC/FCC, built-in interpolation for HCP.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
element_or_structure: Element name or structure
|
|
187
|
+
T_twin: Twinning factor for HCP (0.0=twin-dominated, 1.0=slip-dominated)
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
R_comp ratio
|
|
191
|
+
|
|
192
|
+
Note:
|
|
193
|
+
For HCP, T_twin affects tension/compression asymmetry:
|
|
194
|
+
- T_twin=0.0 → strong asymmetry (Mg: R_comp ≈ 0.6)
|
|
195
|
+
- T_twin=1.0 → symmetric (R_comp ≈ 1.0)
|
|
196
|
+
"""
|
|
197
|
+
structure = ELEMENT_STRUCTURE.get(element_or_structure, element_or_structure)
|
|
198
|
+
|
|
199
|
+
# HCP: Always use built-in interpolation
|
|
200
|
+
if structure == 'HCP':
|
|
201
|
+
R_symmetric = 1.0 # Slip-dominated (symmetric)
|
|
202
|
+
if element_or_structure == 'Mg':
|
|
203
|
+
R_twin = 0.60 # Mg twin-dominated (strong asymmetry)
|
|
204
|
+
elif element_or_structure == 'Zn':
|
|
205
|
+
R_twin = 1.20 # Zn (compression stronger)
|
|
206
|
+
elif element_or_structure == 'Ti':
|
|
207
|
+
R_twin = 1.00 # Ti (mostly symmetric)
|
|
208
|
+
else:
|
|
209
|
+
R_twin = 0.80 # Generic HCP
|
|
210
|
+
|
|
211
|
+
# T_twin=1.0 → symmetric (1.0)
|
|
212
|
+
# T_twin=0.0 → asymmetric (element-specific)
|
|
213
|
+
return R_symmetric * T_twin + R_twin * (1 - T_twin)
|
|
214
|
+
|
|
215
|
+
# BCC/FCC: Use v6.9 if available
|
|
216
|
+
if V69_AVAILABLE and element_or_structure in V69_MATERIALS:
|
|
217
|
+
mat = V69_MATERIALS[element_or_structure]
|
|
218
|
+
return v69_sigma_c_over_sigma_t(mat)
|
|
219
|
+
|
|
220
|
+
# Fallback to built-in
|
|
221
|
+
if element_or_structure in BUILTIN_R_COMP:
|
|
222
|
+
return BUILTIN_R_COMP[element_or_structure]
|
|
223
|
+
else:
|
|
224
|
+
return BUILTIN_R_COMP.get(structure, 1.0)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_v69_material(element: str) -> Optional[object]:
|
|
228
|
+
"""Get v6.9b Material object if available."""
|
|
229
|
+
if V69_AVAILABLE and element in V69_MATERIALS:
|
|
230
|
+
return V69_MATERIALS[element]
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# ==============================================================================
|
|
235
|
+
# Constants (Frozen)
|
|
236
|
+
# ==============================================================================
|
|
237
|
+
|
|
238
|
+
K1_LOCALIZATION = 0.75
|
|
239
|
+
K2_LOCALIZATION = 0.48
|
|
240
|
+
|
|
241
|
+
STANDARD_MODES = {
|
|
242
|
+
'Uniaxial': {'j': 1, 'beta': -0.370, 'w_sigma': 1.246, 'w_tau': 0.319, 'w_c': 0.000},
|
|
243
|
+
'Deep Draw': {'j': 2, 'beta': -0.306, 'w_sigma': 1.354, 'w_tau': 0.458, 'w_c': 0.000},
|
|
244
|
+
'Draw-Plane': {'j': 3, 'beta': -0.169, 'w_sigma': 1.552, 'w_tau': 0.723, 'w_c': 0.000},
|
|
245
|
+
'Plane Strain': {'j': 4, 'beta': 0.000, 'w_sigma': 1.732, 'w_tau': 1.000, 'w_c': 0.000},
|
|
246
|
+
'Plane-Stretch': {'j': 5, 'beta': 0.133, 'w_sigma': 1.829, 'w_tau': 0.813, 'w_c': 0.133},
|
|
247
|
+
'Stretch': {'j': 6, 'beta': 0.247, 'w_sigma': 1.889, 'w_tau': 0.670, 'w_c': 0.247},
|
|
248
|
+
'Equi-biaxial': {'j': 7, 'beta': 0.430, 'w_sigma': 1.949, 'w_tau': 0.469, 'w_c': 0.430},
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
MODE_ORDER = ['Uniaxial', 'Deep Draw', 'Draw-Plane', 'Plane Strain',
|
|
252
|
+
'Plane-Stretch', 'Stretch', 'Equi-biaxial']
|
|
253
|
+
|
|
254
|
+
R_TH_VIRGIN = {'BCC': 0.65, 'FCC': 0.02, 'HCP': 0.20}
|
|
255
|
+
|
|
256
|
+
# Pre-calculate C_j
|
|
257
|
+
LOCALIZATION_COEFFS = {
|
|
258
|
+
mode: 1 + K1_LOCALIZATION * data['beta'] + K2_LOCALIZATION * data['beta']**2
|
|
259
|
+
for mode, data in STANDARD_MODES.items()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
# ==============================================================================
|
|
264
|
+
# FLCMaterial Class
|
|
265
|
+
# ==============================================================================
|
|
266
|
+
|
|
267
|
+
@dataclass
|
|
268
|
+
class FLCMaterial:
|
|
269
|
+
"""Material data for δ-FLC prediction."""
|
|
270
|
+
name: str
|
|
271
|
+
tau_sigma: float
|
|
272
|
+
R_comp: float
|
|
273
|
+
V_eff: float
|
|
274
|
+
structure: str = 'FCC'
|
|
275
|
+
sigma_y: float = 0.0
|
|
276
|
+
base_element: str = ''
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def r_th(self) -> float:
|
|
280
|
+
return R_TH_VIRGIN.get(self.structure, 0.20)
|
|
281
|
+
|
|
282
|
+
@classmethod
|
|
283
|
+
def from_v69(cls,
|
|
284
|
+
name: str,
|
|
285
|
+
flc0: float,
|
|
286
|
+
base_element: Optional[str] = None,
|
|
287
|
+
structure: Optional[str] = None,
|
|
288
|
+
T_twin: float = 1.0,
|
|
289
|
+
sigma_y: float = 0.0) -> 'FLCMaterial':
|
|
290
|
+
"""
|
|
291
|
+
Create FLCMaterial from v6.9 parameters.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
name: Material name
|
|
295
|
+
flc0: Experimental FLC₀ (Plane Strain)
|
|
296
|
+
base_element: Base element ('Fe', 'Cu', 'Al', etc.)
|
|
297
|
+
structure: Crystal structure (auto-detected if base_element given)
|
|
298
|
+
T_twin: Twinning factor for HCP (0.0-1.0)
|
|
299
|
+
sigma_y: Yield stress [MPa]
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
FLCMaterial with calibrated V_eff
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
>>> mat = FLCMaterial.from_v69('SPCC', flc0=0.225, base_element='Fe')
|
|
306
|
+
>>> mat = FLCMaterial.from_v69('Mg_AZ31', flc0=0.265, base_element='Mg', T_twin=0.0)
|
|
307
|
+
"""
|
|
308
|
+
# Determine structure
|
|
309
|
+
if structure is None:
|
|
310
|
+
if base_element:
|
|
311
|
+
structure = ELEMENT_STRUCTURE.get(base_element, 'FCC')
|
|
312
|
+
else:
|
|
313
|
+
structure = 'FCC'
|
|
314
|
+
|
|
315
|
+
# Get multiaxial parameters
|
|
316
|
+
key = base_element if base_element else structure
|
|
317
|
+
tau_sigma = get_tau_sigma(key, T_twin)
|
|
318
|
+
R_comp = get_R_comp(key, T_twin)
|
|
319
|
+
|
|
320
|
+
# Calibrate V_eff from FLC₀
|
|
321
|
+
V_eff = calibrate_V_eff(flc0, tau_sigma, R_comp)
|
|
322
|
+
|
|
323
|
+
return cls(
|
|
324
|
+
name=name,
|
|
325
|
+
tau_sigma=tau_sigma,
|
|
326
|
+
R_comp=R_comp,
|
|
327
|
+
V_eff=V_eff,
|
|
328
|
+
structure=structure,
|
|
329
|
+
sigma_y=sigma_y,
|
|
330
|
+
base_element=base_element or '',
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
# ==============================================================================
|
|
335
|
+
# Core Functions
|
|
336
|
+
# ==============================================================================
|
|
337
|
+
|
|
338
|
+
def calc_R_eff(tau_sigma: float, R_comp: float, mode: str) -> float:
|
|
339
|
+
"""Calculate effective resistance R_j."""
|
|
340
|
+
m = STANDARD_MODES[mode]
|
|
341
|
+
R_eff = m['w_sigma'] + m['w_tau'] / tau_sigma
|
|
342
|
+
if m['w_c'] > 0:
|
|
343
|
+
R_eff += m['w_c'] / R_comp
|
|
344
|
+
return R_eff
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def calc_K_coeff(tau_sigma: float, R_comp: float, mode: str) -> float:
|
|
348
|
+
"""Calculate combined coefficient K_j = C_j / R_j."""
|
|
349
|
+
C_j = LOCALIZATION_COEFFS[mode]
|
|
350
|
+
R_j = calc_R_eff(tau_sigma, R_comp, mode)
|
|
351
|
+
return C_j / R_j
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def calibrate_V_eff(flc0: float, tau_sigma: float, R_comp: float = 1.0) -> float:
|
|
355
|
+
"""Calibrate V_eff from FLC₀ (Plane Strain)."""
|
|
356
|
+
R_ps = calc_R_eff(tau_sigma, R_comp, 'Plane Strain')
|
|
357
|
+
C_ps = LOCALIZATION_COEFFS['Plane Strain'] # = 1.0
|
|
358
|
+
return flc0 * R_ps / C_ps
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def predict_flc_mode(material: Union[str, FLCMaterial], mode: str) -> float:
|
|
362
|
+
"""Predict FLC for a specific mode."""
|
|
363
|
+
if isinstance(material, str):
|
|
364
|
+
mat = FLC_MATERIALS.get(material)
|
|
365
|
+
if mat is None:
|
|
366
|
+
raise ValueError(f"Material '{material}' not found.")
|
|
367
|
+
else:
|
|
368
|
+
mat = material
|
|
369
|
+
|
|
370
|
+
K_j = calc_K_coeff(mat.tau_sigma, mat.R_comp, mode)
|
|
371
|
+
return mat.V_eff * K_j
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
# ==============================================================================
|
|
375
|
+
# Built-in Material Database (Optimized)
|
|
376
|
+
# ==============================================================================
|
|
377
|
+
|
|
378
|
+
FLC_MATERIALS: Dict[str, FLCMaterial] = {
|
|
379
|
+
'Cu': FLCMaterial('Cu', 0.565, 1.00, 1.2235, 'FCC', 69.5, 'Cu'),
|
|
380
|
+
'Ti': FLCMaterial('Ti', 0.546, 1.00, 1.0391, 'HCP', 270.8, 'Ti'),
|
|
381
|
+
'SPCC': FLCMaterial('SPCC', 0.565, 1.00, 0.8024, 'BCC', 237.0, 'Fe'),
|
|
382
|
+
'DP590': FLCMaterial('DP590', 0.565, 1.00, 0.6911, 'BCC', 360.0, 'Fe'),
|
|
383
|
+
'Al5052': FLCMaterial('Al5052', 0.565, 1.00, 0.6189, 'FCC', 85.0, 'Al'),
|
|
384
|
+
'SUS304': FLCMaterial('SUS304', 0.565, 1.00, 1.4234, 'FCC', 275.0, 'Ni'),
|
|
385
|
+
'Mg_AZ31': FLCMaterial('Mg_AZ31', 0.327, 0.60, 1.1798, 'HCP', 136.0, 'Mg'),
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
# ==============================================================================
|
|
390
|
+
# FLC Predictor Class
|
|
391
|
+
# ==============================================================================
|
|
392
|
+
|
|
393
|
+
class FLCPredictor:
|
|
394
|
+
"""
|
|
395
|
+
δ-Theory FLC Predictor (v8.1) - Integrated with v6.9
|
|
396
|
+
|
|
397
|
+
Example:
|
|
398
|
+
>>> flc = FLCPredictor()
|
|
399
|
+
|
|
400
|
+
# Use built-in material
|
|
401
|
+
>>> flc.predict('Cu', 'Plane Strain')
|
|
402
|
+
0.346
|
|
403
|
+
|
|
404
|
+
# Add from v6.9 parameters
|
|
405
|
+
>>> flc.add_from_v69('MySteel', flc0=0.28, base_element='Fe')
|
|
406
|
+
>>> flc.predict('MySteel', 'Uniaxial')
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
def __init__(self):
|
|
410
|
+
self._materials = FLC_MATERIALS.copy()
|
|
411
|
+
|
|
412
|
+
@property
|
|
413
|
+
def v69_available(self) -> bool:
|
|
414
|
+
"""Check if v6.9 is available."""
|
|
415
|
+
return V69_AVAILABLE
|
|
416
|
+
|
|
417
|
+
def add_material(self, mat: FLCMaterial) -> None:
|
|
418
|
+
"""Add custom material."""
|
|
419
|
+
self._materials[mat.name] = mat
|
|
420
|
+
|
|
421
|
+
def add_from_v69(self,
|
|
422
|
+
name: str,
|
|
423
|
+
flc0: float,
|
|
424
|
+
base_element: Optional[str] = None,
|
|
425
|
+
structure: Optional[str] = None,
|
|
426
|
+
T_twin: float = 1.0,
|
|
427
|
+
sigma_y: float = 0.0) -> FLCMaterial:
|
|
428
|
+
"""
|
|
429
|
+
Add material using v6.9 parameters.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
name: Material name
|
|
433
|
+
flc0: Experimental FLC₀
|
|
434
|
+
base_element: Base element ('Fe', 'Cu', 'Al', 'Ti', 'Mg', etc.)
|
|
435
|
+
structure: Crystal structure (auto-detected from base_element)
|
|
436
|
+
T_twin: Twinning factor for HCP (0.0=twin-dominated, 1.0=slip-dominated)
|
|
437
|
+
sigma_y: Yield stress [MPa]
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
Created FLCMaterial
|
|
441
|
+
|
|
442
|
+
Examples:
|
|
443
|
+
# BCC steel
|
|
444
|
+
>>> flc.add_from_v69('SPCC', flc0=0.225, base_element='Fe')
|
|
445
|
+
|
|
446
|
+
# FCC aluminum alloy
|
|
447
|
+
>>> flc.add_from_v69('A5052', flc0=0.165, base_element='Al')
|
|
448
|
+
|
|
449
|
+
# HCP magnesium (twin-dominated)
|
|
450
|
+
>>> flc.add_from_v69('AZ31', flc0=0.265, base_element='Mg', T_twin=0.0)
|
|
451
|
+
|
|
452
|
+
# HCP titanium (slip-dominated)
|
|
453
|
+
>>> flc.add_from_v69('Ti64', flc0=0.30, base_element='Ti', T_twin=1.0)
|
|
454
|
+
"""
|
|
455
|
+
mat = FLCMaterial.from_v69(
|
|
456
|
+
name=name,
|
|
457
|
+
flc0=flc0,
|
|
458
|
+
base_element=base_element,
|
|
459
|
+
structure=structure,
|
|
460
|
+
T_twin=T_twin,
|
|
461
|
+
sigma_y=sigma_y,
|
|
462
|
+
)
|
|
463
|
+
self._materials[name] = mat
|
|
464
|
+
return mat
|
|
465
|
+
|
|
466
|
+
def add_from_flc0(self,
|
|
467
|
+
name: str,
|
|
468
|
+
flc0: float,
|
|
469
|
+
tau_sigma: float,
|
|
470
|
+
R_comp: float = 1.0,
|
|
471
|
+
structure: str = 'FCC',
|
|
472
|
+
sigma_y: float = 0.0) -> FLCMaterial:
|
|
473
|
+
"""Add material with explicit τ/σ and R_comp."""
|
|
474
|
+
V_eff = calibrate_V_eff(flc0, tau_sigma, R_comp)
|
|
475
|
+
mat = FLCMaterial(
|
|
476
|
+
name=name,
|
|
477
|
+
tau_sigma=tau_sigma,
|
|
478
|
+
R_comp=R_comp,
|
|
479
|
+
V_eff=V_eff,
|
|
480
|
+
structure=structure,
|
|
481
|
+
sigma_y=sigma_y,
|
|
482
|
+
)
|
|
483
|
+
self._materials[name] = mat
|
|
484
|
+
return mat
|
|
485
|
+
|
|
486
|
+
def add_from_v69_material(self,
|
|
487
|
+
v69_mat,
|
|
488
|
+
flc0: float,
|
|
489
|
+
name: Optional[str] = None,
|
|
490
|
+
T_twin: float = 1.0) -> FLCMaterial:
|
|
491
|
+
"""
|
|
492
|
+
Add material from v6.9 Material object.
|
|
493
|
+
|
|
494
|
+
Args:
|
|
495
|
+
v69_mat: v6.9 Material object (has .structure, .sigma_y, etc.)
|
|
496
|
+
flc0: Experimental FLC₀
|
|
497
|
+
name: Material name (default: v69_mat.name if available)
|
|
498
|
+
T_twin: Twinning factor for HCP
|
|
499
|
+
|
|
500
|
+
Returns:
|
|
501
|
+
Created FLCMaterial
|
|
502
|
+
|
|
503
|
+
Example:
|
|
504
|
+
>>> from unified_yield_fatigue_v6_9 import MATERIALS
|
|
505
|
+
>>> flc.add_from_v69_material(MATERIALS['Fe'], flc0=0.225, name='SPCC')
|
|
506
|
+
"""
|
|
507
|
+
# Extract info from v6.9 Material
|
|
508
|
+
mat_name = name or getattr(v69_mat, 'name', 'Unknown')
|
|
509
|
+
structure = getattr(v69_mat, 'structure', 'FCC')
|
|
510
|
+
sigma_y = getattr(v69_mat, 'sigma_y', 0.0)
|
|
511
|
+
|
|
512
|
+
# Get τ/σ and R_comp from v6.9 functions or built-in
|
|
513
|
+
tau_sigma = get_tau_sigma(structure, T_twin)
|
|
514
|
+
R_comp = get_R_comp(structure, T_twin)
|
|
515
|
+
|
|
516
|
+
# Calibrate V_eff
|
|
517
|
+
V_eff = calibrate_V_eff(flc0, tau_sigma, R_comp)
|
|
518
|
+
|
|
519
|
+
mat = FLCMaterial(
|
|
520
|
+
name=mat_name,
|
|
521
|
+
tau_sigma=tau_sigma,
|
|
522
|
+
R_comp=R_comp,
|
|
523
|
+
V_eff=V_eff,
|
|
524
|
+
structure=structure,
|
|
525
|
+
sigma_y=sigma_y,
|
|
526
|
+
base_element=getattr(v69_mat, 'element', ''),
|
|
527
|
+
)
|
|
528
|
+
self._materials[mat_name] = mat
|
|
529
|
+
return mat
|
|
530
|
+
|
|
531
|
+
def get_material(self, name: str) -> FLCMaterial:
|
|
532
|
+
"""Get material by name."""
|
|
533
|
+
if name not in self._materials:
|
|
534
|
+
available = list(self._materials.keys())
|
|
535
|
+
raise ValueError(f"Material '{name}' not found. Available: {available}")
|
|
536
|
+
return self._materials[name]
|
|
537
|
+
|
|
538
|
+
def list_materials(self) -> List[str]:
|
|
539
|
+
"""List available materials."""
|
|
540
|
+
return list(self._materials.keys())
|
|
541
|
+
|
|
542
|
+
def predict(self,
|
|
543
|
+
material: Union[str, FLCMaterial],
|
|
544
|
+
mode: str,
|
|
545
|
+
include_breakdown: bool = False) -> Union[float, Tuple[float, Dict]]:
|
|
546
|
+
"""Predict FLC for a mode."""
|
|
547
|
+
if isinstance(material, str):
|
|
548
|
+
mat = self.get_material(material)
|
|
549
|
+
else:
|
|
550
|
+
mat = material
|
|
551
|
+
|
|
552
|
+
m = STANDARD_MODES[mode]
|
|
553
|
+
C_j = LOCALIZATION_COEFFS[mode]
|
|
554
|
+
R_j = calc_R_eff(mat.tau_sigma, mat.R_comp, mode)
|
|
555
|
+
K_j = C_j / R_j
|
|
556
|
+
eps1 = mat.V_eff * K_j
|
|
557
|
+
|
|
558
|
+
if include_breakdown:
|
|
559
|
+
return eps1, {
|
|
560
|
+
'mode': mode, 'j': m['j'], 'beta': m['beta'],
|
|
561
|
+
'C_j': C_j, 'R_j': R_j, 'K_j': K_j,
|
|
562
|
+
'V_eff': mat.V_eff, 'tau_sigma': mat.tau_sigma, 'R_comp': mat.R_comp,
|
|
563
|
+
}
|
|
564
|
+
return eps1
|
|
565
|
+
|
|
566
|
+
def predict_all_modes(self, material: Union[str, FLCMaterial]) -> Dict[str, float]:
|
|
567
|
+
"""Predict FLC for all 7 modes."""
|
|
568
|
+
return {mode: self.predict(material, mode) for mode in MODE_ORDER}
|
|
569
|
+
|
|
570
|
+
def predict_curve(self, material: Union[str, FLCMaterial]) -> Tuple[np.ndarray, np.ndarray]:
|
|
571
|
+
"""Predict FLC curve."""
|
|
572
|
+
predictions = self.predict_all_modes(material)
|
|
573
|
+
betas = np.array([STANDARD_MODES[m]['beta'] for m in MODE_ORDER])
|
|
574
|
+
eps1s = np.array([predictions[m] for m in MODE_ORDER])
|
|
575
|
+
return betas, eps1s
|
|
576
|
+
|
|
577
|
+
def flc0(self, material: Union[str, FLCMaterial]) -> float:
|
|
578
|
+
"""Get FLC₀ (Plane Strain)."""
|
|
579
|
+
return self.predict(material, 'Plane Strain')
|
|
580
|
+
|
|
581
|
+
def summary(self, material: Union[str, FLCMaterial]) -> str:
|
|
582
|
+
"""Generate summary report."""
|
|
583
|
+
if isinstance(material, str):
|
|
584
|
+
mat = self.get_material(material)
|
|
585
|
+
else:
|
|
586
|
+
mat = material
|
|
587
|
+
|
|
588
|
+
lines = [
|
|
589
|
+
f"δ-FLC Summary: {mat.name}",
|
|
590
|
+
"=" * 55,
|
|
591
|
+
f"Structure: {mat.structure}",
|
|
592
|
+
f"Base element: {mat.base_element}" if mat.base_element else "",
|
|
593
|
+
f"σ_y: {mat.sigma_y:.1f} MPa" if mat.sigma_y > 0 else "",
|
|
594
|
+
f"τ/σ: {mat.tau_sigma:.4f}",
|
|
595
|
+
f"R_comp: {mat.R_comp:.2f}",
|
|
596
|
+
f"|V|_eff: {mat.V_eff:.4f}",
|
|
597
|
+
"",
|
|
598
|
+
"FLC Predictions:",
|
|
599
|
+
"-" * 55,
|
|
600
|
+
f"{'Mode':<15} {'β':>7} {'C_j':>7} {'R_j':>7} {'K_j':>7} {'ε₁':>8}",
|
|
601
|
+
"-" * 55,
|
|
602
|
+
]
|
|
603
|
+
|
|
604
|
+
for mode in MODE_ORDER:
|
|
605
|
+
eps1, bd = self.predict(mat, mode, include_breakdown=True)
|
|
606
|
+
lines.append(
|
|
607
|
+
f"{mode:<15} {bd['beta']:>7.3f} {bd['C_j']:>7.4f} "
|
|
608
|
+
f"{bd['R_j']:>7.3f} {bd['K_j']:>7.4f} {eps1:>8.4f}"
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
lines.extend(["-" * 55, f"FLC₀: {self.flc0(mat):.4f}"])
|
|
612
|
+
return '\n'.join(filter(None, lines))
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
# ==============================================================================
|
|
616
|
+
# Convenience Functions
|
|
617
|
+
# ==============================================================================
|
|
618
|
+
|
|
619
|
+
def predict_flc(material: str, mode: str = 'Plane Strain') -> float:
|
|
620
|
+
"""Quick FLC prediction."""
|
|
621
|
+
return FLCPredictor().predict(material, mode)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def predict_flc_curve(material: str) -> Tuple[np.ndarray, np.ndarray]:
|
|
625
|
+
"""Quick FLC curve."""
|
|
626
|
+
return FLCPredictor().predict_curve(material)
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def get_flc0(material: str) -> float:
|
|
630
|
+
"""Get FLC₀."""
|
|
631
|
+
return FLCPredictor().flc0(material)
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
def create_material_from_v69(name: str, flc0: float, base_element: str,
|
|
635
|
+
T_twin: float = 1.0) -> FLCMaterial:
|
|
636
|
+
"""Create material using v6.9 parameters."""
|
|
637
|
+
return FLCMaterial.from_v69(name, flc0, base_element, T_twin=T_twin)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
# ==============================================================================
|
|
641
|
+
# Demo
|
|
642
|
+
# ==============================================================================
|
|
643
|
+
|
|
644
|
+
def demo():
|
|
645
|
+
"""Demonstration of v8.1 capabilities."""
|
|
646
|
+
|
|
647
|
+
print("="*70)
|
|
648
|
+
print("δ-Theory FLC v8.1: Integrated with v6.9")
|
|
649
|
+
print("="*70)
|
|
650
|
+
print(f"\nv6.9 available: {V69_AVAILABLE}")
|
|
651
|
+
|
|
652
|
+
flc = FLCPredictor()
|
|
653
|
+
|
|
654
|
+
# 1. Built-in materials
|
|
655
|
+
print("\n[1] Built-in Materials")
|
|
656
|
+
print("-"*70)
|
|
657
|
+
print(f"Available: {flc.list_materials()}")
|
|
658
|
+
|
|
659
|
+
# 2. Add from v6.9 parameters
|
|
660
|
+
print("\n[2] Add Materials from v6.9 Parameters")
|
|
661
|
+
print("-"*70)
|
|
662
|
+
|
|
663
|
+
# BCC steel example
|
|
664
|
+
mat1 = flc.add_from_v69('NewSteel', flc0=0.28, base_element='Fe')
|
|
665
|
+
print(f"Added: {mat1.name}")
|
|
666
|
+
print(f" τ/σ = {mat1.tau_sigma:.4f} (from Fe/BCC)")
|
|
667
|
+
print(f" R_comp = {mat1.R_comp:.2f}")
|
|
668
|
+
print(f" V_eff = {mat1.V_eff:.4f} (calibrated from FLC₀=0.28)")
|
|
669
|
+
|
|
670
|
+
# HCP Mg example (twin-dominated)
|
|
671
|
+
mat2 = flc.add_from_v69('MgAlloy', flc0=0.25, base_element='Mg', T_twin=0.0)
|
|
672
|
+
print(f"\nAdded: {mat2.name}")
|
|
673
|
+
print(f" τ/σ = {mat2.tau_sigma:.4f} (from Mg/HCP, T_twin=0)")
|
|
674
|
+
print(f" R_comp = {mat2.R_comp:.2f}")
|
|
675
|
+
print(f" V_eff = {mat2.V_eff:.4f}")
|
|
676
|
+
|
|
677
|
+
# 3. Simulate v6.9 Material object integration
|
|
678
|
+
print("\n[3] v6.9 Material Object Integration (Simulated)")
|
|
679
|
+
print("-"*70)
|
|
680
|
+
|
|
681
|
+
# Create a mock v6.9 Material object
|
|
682
|
+
class MockV69Material:
|
|
683
|
+
def __init__(self, name, structure, sigma_y=0.0, element=''):
|
|
684
|
+
self.name = name
|
|
685
|
+
self.structure = structure
|
|
686
|
+
self.sigma_y = sigma_y
|
|
687
|
+
self.element = element
|
|
688
|
+
|
|
689
|
+
# Simulate v6.9 Material
|
|
690
|
+
v69_fe = MockV69Material('Fe_BCC', 'BCC', sigma_y=250.0, element='Fe')
|
|
691
|
+
mat3 = flc.add_from_v69_material(v69_fe, flc0=0.225, name='SPCC_v69')
|
|
692
|
+
print(f"Added from v6.9 Material: {mat3.name}")
|
|
693
|
+
print(f" Structure: {mat3.structure}")
|
|
694
|
+
print(f" σ_y: {mat3.sigma_y:.1f} MPa")
|
|
695
|
+
print(f" τ/σ = {mat3.tau_sigma:.4f}")
|
|
696
|
+
print(f" R_comp = {mat3.R_comp:.2f}")
|
|
697
|
+
print(f" V_eff = {mat3.V_eff:.4f}")
|
|
698
|
+
|
|
699
|
+
# 4. Predictions
|
|
700
|
+
print("\n[4] FLC Predictions")
|
|
701
|
+
print("-"*70)
|
|
702
|
+
|
|
703
|
+
for mat_name in ['NewSteel', 'MgAlloy', 'SPCC_v69']:
|
|
704
|
+
print(f"\n{mat_name}:")
|
|
705
|
+
for mode in ['Uniaxial', 'Plane Strain', 'Equi-biaxial']:
|
|
706
|
+
eps1 = flc.predict(mat_name, mode)
|
|
707
|
+
print(f" {mode}: ε₁ = {eps1:.4f}")
|
|
708
|
+
|
|
709
|
+
# 5. Full summary
|
|
710
|
+
print("\n[5] Material Summary: SPCC_v69")
|
|
711
|
+
print("-"*70)
|
|
712
|
+
print(flc.summary('SPCC_v69'))
|
|
713
|
+
|
|
714
|
+
# 6. τ/σ comparison (pure metal native values)
|
|
715
|
+
print("\n[6] τ/σ Values by Base Element (Pure Metal Native)")
|
|
716
|
+
print("-"*70)
|
|
717
|
+
print(f"{'Element':<10} {'Structure':<10} {'τ/σ':>10} {'R_comp':>10} {'Note':>15}")
|
|
718
|
+
print("-"*60)
|
|
719
|
+
|
|
720
|
+
# Pure metals: BCC/FCC use T_twin=1.0, HCP uses native characteristic
|
|
721
|
+
elements_info = [
|
|
722
|
+
('Fe', 'BCC', 1.0, ''),
|
|
723
|
+
('Cu', 'FCC', 1.0, ''),
|
|
724
|
+
('Al', 'FCC', 1.0, ''),
|
|
725
|
+
('Ni', 'FCC', 1.0, ''),
|
|
726
|
+
('Ti', 'HCP', 0.0, 'HCP, c/a effect'), # Ti native
|
|
727
|
+
('Mg', 'HCP', 0.0, 'twin-dominant'), # Mg native
|
|
728
|
+
]
|
|
729
|
+
|
|
730
|
+
for elem, struct, T_twin, note in elements_info:
|
|
731
|
+
tau_s = get_tau_sigma(elem, T_twin)
|
|
732
|
+
r_c = get_R_comp(elem, T_twin)
|
|
733
|
+
print(f"{elem:<10} {struct:<10} {tau_s:>10.4f} {r_c:>10.2f} {note:>15}")
|
|
734
|
+
|
|
735
|
+
# 7. HCP T_twin interpolation
|
|
736
|
+
print("\n[7] HCP τ/σ vs T_twin (Mg)")
|
|
737
|
+
print("-"*70)
|
|
738
|
+
for T_twin in [0.0, 0.25, 0.5, 0.75, 1.0]:
|
|
739
|
+
tau_s = get_tau_sigma('Mg', T_twin)
|
|
740
|
+
r_c = get_R_comp('Mg', T_twin)
|
|
741
|
+
print(f" T_twin = {T_twin:.2f} → τ/σ = {tau_s:.4f}, R_comp = {r_c:.2f}")
|
|
742
|
+
|
|
743
|
+
# 8. Quick usage example
|
|
744
|
+
print("\n[8] Quick Usage Example")
|
|
745
|
+
print("-"*70)
|
|
746
|
+
print("""
|
|
747
|
+
# Basic usage:
|
|
748
|
+
from unified_flc_v8_1 import FLCPredictor, predict_flc
|
|
749
|
+
|
|
750
|
+
# Use built-in material
|
|
751
|
+
eps1 = predict_flc('Cu', 'Plane Strain') # 0.346
|
|
752
|
+
|
|
753
|
+
# Add new material from element
|
|
754
|
+
flc = FLCPredictor()
|
|
755
|
+
flc.add_from_v69('MySteel', flc0=0.28, base_element='Fe')
|
|
756
|
+
curve = flc.predict_curve('MySteel')
|
|
757
|
+
|
|
758
|
+
# Add from explicit parameters
|
|
759
|
+
flc.add_from_flc0('Custom', flc0=0.30, tau_sigma=0.565, R_comp=1.0)
|
|
760
|
+
|
|
761
|
+
# If v6.9 is available:
|
|
762
|
+
# from unified_yield_fatigue_v6_9 import MATERIALS
|
|
763
|
+
# flc.add_from_v69_material(MATERIALS['Fe'], flc0=0.225, name='SPCC')
|
|
764
|
+
""")
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
if __name__ == '__main__':
|
|
768
|
+
demo()
|