delta-theory 6.9.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.
- apps/__init__.py +6 -0
- apps/delta_fatigue_app.py +337 -0
- core/Universal_Lindemann.py +422 -0
- core/__init__.py +35 -0
- core/dbt_unified.py +690 -0
- core/materials.py +688 -0
- core/unified_yield_fatigue_v6_9.py +762 -0
- delta_theory-6.9.0.dist-info/METADATA +640 -0
- delta_theory-6.9.0.dist-info/RECORD +15 -0
- delta_theory-6.9.0.dist-info/WHEEL +5 -0
- delta_theory-6.9.0.dist-info/entry_points.txt +3 -0
- delta_theory-6.9.0.dist-info/licenses/LICENSE +26 -0
- delta_theory-6.9.0.dist-info/top_level.txt +3 -0
- validation/__init__.py +10 -0
- validation/fatigue_redis_api.py +334 -0
apps/__init__.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
δ理論 疲労予測 Web App (Streamlit)
|
|
4
|
+
v6.8 Structure Presets + A_int/A_ext 分離
|
|
5
|
+
|
|
6
|
+
デモURL: streamlit run delta_fatigue_app.py
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import streamlit as st
|
|
10
|
+
import numpy as np
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
|
|
14
|
+
# ===============================
|
|
15
|
+
# v6.8 Core (embedded)
|
|
16
|
+
# ===============================
|
|
17
|
+
eV_to_J = 1.602176634e-19
|
|
18
|
+
k_B = 1.380649e-23
|
|
19
|
+
PI = np.pi
|
|
20
|
+
|
|
21
|
+
STRUCTURE_PRESETS = {
|
|
22
|
+
"BCC": {"r_th": 0.65, "n_cl": 10, "desc": "Body-Centered Cubic (Fe, W) - 明確な疲労限度"},
|
|
23
|
+
"FCC": {"r_th": 0.02, "n_cl": 7, "desc": "Face-Centered Cubic (Cu, Al, Ni) - 疲労限度なし"},
|
|
24
|
+
"HCP": {"r_th": 0.40, "n_cl": 8, "desc": "Hexagonal Close-Packed (Ti, Mg) - 中間的挙動"},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
MATERIAL_DB = {
|
|
28
|
+
"Fe": {"structure": "BCC", "E_bond_eV": 4.28, "f_d": 1.5, "a_lat_m": 2.92e-10,
|
|
29
|
+
"alpha0": 0.289, "T_m_K": 1811, "delta_L": 0.18, "M_taylor": 3.0,
|
|
30
|
+
"tau_sigma_ratio": 0.565, "color": "#1f77b4"},
|
|
31
|
+
"W": {"structure": "BCC", "E_bond_eV": 8.90, "f_d": 1.3, "a_lat_m": 3.16e-10,
|
|
32
|
+
"alpha0": 0.289, "T_m_K": 3695, "delta_L": 0.18, "M_taylor": 3.0,
|
|
33
|
+
"tau_sigma_ratio": 0.565, "color": "#17becf"},
|
|
34
|
+
"Cu": {"structure": "FCC", "E_bond_eV": 3.49, "f_d": 2.0, "a_lat_m": 3.61e-10,
|
|
35
|
+
"alpha0": 0.289, "T_m_K": 1358, "delta_L": 0.18, "M_taylor": 3.06,
|
|
36
|
+
"tau_sigma_ratio": 0.565, "color": "#d62728"},
|
|
37
|
+
"Al": {"structure": "FCC", "E_bond_eV": 3.39, "f_d": 1.0, "a_lat_m": 4.05e-10,
|
|
38
|
+
"alpha0": 0.289, "T_m_K": 933, "delta_L": 0.18, "M_taylor": 3.06,
|
|
39
|
+
"tau_sigma_ratio": 0.565, "color": "#2ca02c"},
|
|
40
|
+
"Ni": {"structure": "FCC", "E_bond_eV": 4.44, "f_d": 1.8, "a_lat_m": 3.52e-10,
|
|
41
|
+
"alpha0": 0.289, "T_m_K": 1728, "delta_L": 0.18, "M_taylor": 3.06,
|
|
42
|
+
"tau_sigma_ratio": 0.565, "color": "#ff7f0e"},
|
|
43
|
+
"Ti": {"structure": "HCP", "E_bond_eV": 4.85, "f_d": 1.2, "a_lat_m": 2.95e-10,
|
|
44
|
+
"alpha0": 0.289, "T_m_K": 1941, "delta_L": 0.18, "M_taylor": 4.0,
|
|
45
|
+
"tau_sigma_ratio": 0.50, "color": "#9467bd"},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def get_burgers(mat):
|
|
49
|
+
struct, a = mat["structure"], mat["a_lat_m"]
|
|
50
|
+
if struct == "BCC": return a * np.sqrt(3) / 2
|
|
51
|
+
elif struct == "FCC": return a / np.sqrt(2)
|
|
52
|
+
else: return a
|
|
53
|
+
|
|
54
|
+
def get_V_act(mat):
|
|
55
|
+
return get_burgers(mat) ** 3
|
|
56
|
+
|
|
57
|
+
def calc_A_int(mat, T_K=300.0):
|
|
58
|
+
E_bond = mat["E_bond_eV"] * eV_to_J
|
|
59
|
+
E_eff = E_bond * mat["alpha0"] * mat["f_d"]
|
|
60
|
+
V_act = get_V_act(mat)
|
|
61
|
+
T_m = mat["T_m_K"]
|
|
62
|
+
tau_sigma = mat["tau_sigma_ratio"]
|
|
63
|
+
A_raw = tau_sigma * E_eff / (V_act * k_B * T_m)
|
|
64
|
+
# Normalize to Fe
|
|
65
|
+
Fe = MATERIAL_DB["Fe"]
|
|
66
|
+
E_Fe = Fe["E_bond_eV"] * eV_to_J * Fe["alpha0"] * Fe["f_d"]
|
|
67
|
+
V_Fe = get_V_act(Fe)
|
|
68
|
+
A_Fe = Fe["tau_sigma_ratio"] * E_Fe / (V_Fe * k_B * Fe["T_m_K"])
|
|
69
|
+
return A_raw / A_Fe
|
|
70
|
+
|
|
71
|
+
def sigma_yield(mat, T_K, d_m, beta_hp=3.5e-3):
|
|
72
|
+
E_bond = mat["E_bond_eV"] * eV_to_J
|
|
73
|
+
E_eff = E_bond * mat["alpha0"] * mat["f_d"]
|
|
74
|
+
V_act = get_V_act(mat)
|
|
75
|
+
delta_L = mat["delta_L"]
|
|
76
|
+
M = mat["M_taylor"]
|
|
77
|
+
T_m = mat["T_m_K"]
|
|
78
|
+
HP = max(1e-9, 1.0 - T_K / T_m)
|
|
79
|
+
A0 = (E_eff / V_act) * delta_L / (2 * PI * M)
|
|
80
|
+
sigma0 = A0 * HP
|
|
81
|
+
R_block = 1.0 + beta_hp / np.sqrt(d_m)
|
|
82
|
+
return sigma0 * R_block
|
|
83
|
+
|
|
84
|
+
def N_fail_CL(sigma_max, R_ratio, T_K, d_m, mat, A_ext, D_req=0.78):
|
|
85
|
+
struct = mat["structure"]
|
|
86
|
+
preset = STRUCTURE_PRESETS[struct]
|
|
87
|
+
r_th, n_cl = preset["r_th"], preset["n_cl"]
|
|
88
|
+
A_int = calc_A_int(mat, T_K)
|
|
89
|
+
A_total = A_int * A_ext
|
|
90
|
+
|
|
91
|
+
sigma_amp = 0.5 * sigma_max * (1 - R_ratio)
|
|
92
|
+
sigma_y = sigma_yield(mat, T_K, d_m)
|
|
93
|
+
r = sigma_amp / sigma_y
|
|
94
|
+
|
|
95
|
+
if r <= r_th:
|
|
96
|
+
return float("inf"), r, r_th, n_cl, A_int, sigma_y
|
|
97
|
+
|
|
98
|
+
k = A_total * (r - r_th) ** n_cl
|
|
99
|
+
if k <= 0:
|
|
100
|
+
return float("inf"), r, r_th, n_cl, A_int, sigma_y
|
|
101
|
+
|
|
102
|
+
N_fail = D_req / k
|
|
103
|
+
return N_fail, r, r_th, n_cl, A_int, sigma_y
|
|
104
|
+
|
|
105
|
+
def calibrate_A_ext(sigma_max, R_ratio, N_target, T_K, d_m, mat, D_req=0.78):
|
|
106
|
+
struct = mat["structure"]
|
|
107
|
+
preset = STRUCTURE_PRESETS[struct]
|
|
108
|
+
r_th, n_cl = preset["r_th"], preset["n_cl"]
|
|
109
|
+
A_int = calc_A_int(mat, T_K)
|
|
110
|
+
|
|
111
|
+
sigma_amp = 0.5 * sigma_max * (1 - R_ratio)
|
|
112
|
+
sigma_y = sigma_yield(mat, T_K, d_m)
|
|
113
|
+
r = sigma_amp / sigma_y
|
|
114
|
+
|
|
115
|
+
if r <= r_th:
|
|
116
|
+
return None, r, r_th, n_cl, A_int, sigma_y, "Error: r ≤ r_th (疲労限度以下)"
|
|
117
|
+
|
|
118
|
+
A_total_need = D_req / (N_target * (r - r_th) ** n_cl)
|
|
119
|
+
A_ext = A_total_need / A_int
|
|
120
|
+
return A_ext, r, r_th, n_cl, A_int, sigma_y, "OK"
|
|
121
|
+
|
|
122
|
+
# ===============================
|
|
123
|
+
# Streamlit App
|
|
124
|
+
# ===============================
|
|
125
|
+
|
|
126
|
+
st.set_page_config(
|
|
127
|
+
page_title="δ理論 疲労予測 v6.8",
|
|
128
|
+
page_icon="🔬",
|
|
129
|
+
layout="wide"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
st.title("🔬 δ理論 疲労予測システム v6.8")
|
|
133
|
+
st.markdown("""
|
|
134
|
+
**結晶構造から疲労限度を予測** | フィッティングパラメータ: **0.5個**(1点校正のみ)
|
|
135
|
+
""")
|
|
136
|
+
|
|
137
|
+
# Sidebar
|
|
138
|
+
st.sidebar.header("⚙️ 設定")
|
|
139
|
+
|
|
140
|
+
tab1, tab2, tab3 = st.tabs(["📊 S-N曲線予測", "🎯 A_ext キャリブレーション", "📚 理論説明"])
|
|
141
|
+
|
|
142
|
+
# ========== Tab 1: S-N Prediction ==========
|
|
143
|
+
with tab1:
|
|
144
|
+
col1, col2 = st.columns([1, 2])
|
|
145
|
+
|
|
146
|
+
with col1:
|
|
147
|
+
st.subheader("パラメータ設定")
|
|
148
|
+
|
|
149
|
+
materials = st.multiselect(
|
|
150
|
+
"材料選択",
|
|
151
|
+
options=list(MATERIAL_DB.keys()),
|
|
152
|
+
default=["Fe", "Cu", "Al", "Ni"]
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
T_K = st.slider("温度 T [K]", 200, 800, 300)
|
|
156
|
+
d_um = st.slider("粒径 d [μm]", 1, 100, 30)
|
|
157
|
+
A_ext = st.number_input("A_ext (校正値)", value=2.46e-4, format="%.2e")
|
|
158
|
+
R_ratio = st.slider("応力比 R", -1.0, 0.5, -1.0, 0.1)
|
|
159
|
+
|
|
160
|
+
st.divider()
|
|
161
|
+
sigma_min = st.slider("σ_min [MPa]", 10, 200, 30)
|
|
162
|
+
sigma_max = st.slider("σ_max [MPa]", 100, 500, 300)
|
|
163
|
+
n_points = st.slider("計算点数", 10, 50, 25)
|
|
164
|
+
|
|
165
|
+
with col2:
|
|
166
|
+
if st.button("🚀 S-N曲線を計算", type="primary"):
|
|
167
|
+
d_m = d_um * 1e-6
|
|
168
|
+
sigma_list = np.linspace(sigma_min * 1e6, sigma_max * 1e6, n_points)
|
|
169
|
+
|
|
170
|
+
fig, ax = plt.subplots(figsize=(10, 7))
|
|
171
|
+
|
|
172
|
+
results_data = []
|
|
173
|
+
|
|
174
|
+
for mat_name in materials:
|
|
175
|
+
mat = MATERIAL_DB.get(mat_name)
|
|
176
|
+
if mat is None:
|
|
177
|
+
continue
|
|
178
|
+
|
|
179
|
+
N_list = []
|
|
180
|
+
for sig in sigma_list:
|
|
181
|
+
N, r, r_th, n_cl, A_int, sigma_y = N_fail_CL(sig, R_ratio, T_K, d_m, mat, A_ext)
|
|
182
|
+
N_list.append(N)
|
|
183
|
+
|
|
184
|
+
# Filter finite values
|
|
185
|
+
valid = [(s, N) for s, N in zip(sigma_list, N_list) if N < 1e20]
|
|
186
|
+
|
|
187
|
+
if valid:
|
|
188
|
+
x = [s/1e6 for s, N in valid]
|
|
189
|
+
y = [N for s, N in valid]
|
|
190
|
+
ax.loglog(x, y, 'o-', color=mat.get("color", "black"),
|
|
191
|
+
linewidth=2.5, markersize=6,
|
|
192
|
+
label=f'{mat_name} ({mat["structure"]}, r_th={STRUCTURE_PRESETS[mat["structure"]]["r_th"]:.2f})')
|
|
193
|
+
|
|
194
|
+
struct = mat["structure"]
|
|
195
|
+
A_int_val = calc_A_int(mat, T_K)
|
|
196
|
+
results_data.append({
|
|
197
|
+
"材料": mat_name,
|
|
198
|
+
"構造": struct,
|
|
199
|
+
"r_th": STRUCTURE_PRESETS[struct]["r_th"],
|
|
200
|
+
"n_cl": STRUCTURE_PRESETS[struct]["n_cl"],
|
|
201
|
+
"A_int": f"{A_int_val:.3f}",
|
|
202
|
+
"有限寿命点": f"{len(valid)}/{n_points}",
|
|
203
|
+
"疲労限度": "✅ あり" if STRUCTURE_PRESETS[struct]["r_th"] > 0.1 else "❌ なし"
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
ax.set_xlabel('Maximum Stress σ_max [MPa]', fontsize=12)
|
|
207
|
+
ax.set_ylabel('Cycles to Failure N_f', fontsize=12)
|
|
208
|
+
ax.set_title(f'δ理論 S-N曲線予測 (v6.8)\nT={T_K}K, d={d_um}μm, R={R_ratio}', fontsize=14)
|
|
209
|
+
ax.legend(loc='upper right', fontsize=10)
|
|
210
|
+
ax.grid(True, which='both', alpha=0.3)
|
|
211
|
+
ax.set_ylim(1e2, 1e15)
|
|
212
|
+
|
|
213
|
+
st.pyplot(fig)
|
|
214
|
+
|
|
215
|
+
st.subheader("予測結果サマリー")
|
|
216
|
+
st.dataframe(pd.DataFrame(results_data), use_container_width=True)
|
|
217
|
+
|
|
218
|
+
st.success(f"""
|
|
219
|
+
**計算完了!**
|
|
220
|
+
- 材料数: {len(materials)}
|
|
221
|
+
- A_ext: {A_ext:.2e}(1点校正パラメータ)
|
|
222
|
+
- r_th, n_cl は構造プリセットから自動設定(フィッティングなし)
|
|
223
|
+
""")
|
|
224
|
+
|
|
225
|
+
# ========== Tab 2: Calibration ==========
|
|
226
|
+
with tab2:
|
|
227
|
+
st.subheader("A_ext の1点校正")
|
|
228
|
+
st.markdown("""
|
|
229
|
+
実験データ1点から **A_ext** を逆算します。
|
|
230
|
+
この値を使って他の材料・条件の S-N 曲線を予測できます。
|
|
231
|
+
""")
|
|
232
|
+
|
|
233
|
+
col1, col2 = st.columns(2)
|
|
234
|
+
|
|
235
|
+
with col1:
|
|
236
|
+
cal_material = st.selectbox("材料", list(MATERIAL_DB.keys()), index=0)
|
|
237
|
+
cal_T_K = st.slider("温度 T [K]", 200, 800, 300, key="cal_T")
|
|
238
|
+
cal_d_um = st.slider("粒径 d [μm]", 1, 100, 30, key="cal_d")
|
|
239
|
+
|
|
240
|
+
with col2:
|
|
241
|
+
cal_sigma_max = st.number_input("σ_max [MPa]", value=244.0)
|
|
242
|
+
cal_R_ratio = st.slider("応力比 R", -1.0, 0.5, -1.0, 0.1, key="cal_R")
|
|
243
|
+
cal_N_target = st.number_input("N_target [cycles]", value=7.25e7, format="%.2e")
|
|
244
|
+
|
|
245
|
+
if st.button("🔧 A_ext を計算", type="primary"):
|
|
246
|
+
mat = MATERIAL_DB[cal_material].copy()
|
|
247
|
+
d_m = cal_d_um * 1e-6
|
|
248
|
+
|
|
249
|
+
A_ext_cal, r, r_th, n_cl, A_int, sigma_y, status = calibrate_A_ext(
|
|
250
|
+
cal_sigma_max * 1e6, cal_R_ratio, cal_N_target, cal_T_K, d_m, mat
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
if status == "OK":
|
|
254
|
+
st.success(f"### A_ext = {A_ext_cal:.6e}")
|
|
255
|
+
|
|
256
|
+
col1, col2, col3 = st.columns(3)
|
|
257
|
+
with col1:
|
|
258
|
+
st.metric("σ_y (δ理論)", f"{sigma_y/1e6:.1f} MPa")
|
|
259
|
+
st.metric("r = σ_a/σ_y", f"{r:.4f}")
|
|
260
|
+
with col2:
|
|
261
|
+
st.metric("r_th (プリセット)", f"{r_th:.2f}")
|
|
262
|
+
st.metric("n_cl (プリセット)", f"{n_cl}")
|
|
263
|
+
with col3:
|
|
264
|
+
st.metric("A_int (δスケール)", f"{A_int:.4f}")
|
|
265
|
+
st.metric("A_total", f"{A_int * A_ext_cal:.6e}")
|
|
266
|
+
else:
|
|
267
|
+
st.error(status)
|
|
268
|
+
|
|
269
|
+
# ========== Tab 3: Theory ==========
|
|
270
|
+
with tab3:
|
|
271
|
+
st.subheader("δ理論とは")
|
|
272
|
+
|
|
273
|
+
st.markdown("""
|
|
274
|
+
### 核心方程式
|
|
275
|
+
""")
|
|
276
|
+
|
|
277
|
+
st.latex(r"\Lambda = \frac{K}{|V|_{\text{eff}}}")
|
|
278
|
+
|
|
279
|
+
st.markdown("""
|
|
280
|
+
- **K**: 破壊駆動エネルギー(外力)
|
|
281
|
+
- **|V|_eff**: 有効凝集エネルギー(材料抵抗)
|
|
282
|
+
- **Λ = 1**: 臨界条件(破壊発生)
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### v6.8 疲労モデルの特徴
|
|
287
|
+
|
|
288
|
+
**ダメージ蓄積(非マルコフ的):**
|
|
289
|
+
""")
|
|
290
|
+
|
|
291
|
+
st.latex(r"\frac{dD}{dN} = A_{\text{cl}} \times (r - r_{th})^{n_{cl}} \times (1-D)^{m_{cl}}")
|
|
292
|
+
|
|
293
|
+
st.markdown("""
|
|
294
|
+
- **r = σ_a / σ_y**: 正規化応力振幅
|
|
295
|
+
- **r_th**: 疲労限度閾値(構造依存)
|
|
296
|
+
- **r ≤ r_th → dD/dN = 0**: 疲労限度が自然に出る!
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
### 構造プリセット
|
|
301
|
+
""")
|
|
302
|
+
|
|
303
|
+
preset_df = pd.DataFrame([
|
|
304
|
+
{"構造": "BCC", "r_th": 0.65, "n_cl": 10, "疲労限度": "✅ 明確にあり", "例": "Fe, W, Mo"},
|
|
305
|
+
{"構造": "FCC", "r_th": 0.02, "n_cl": 7, "疲労限度": "❌ なし/曖昧", "例": "Cu, Al, Ni, Au"},
|
|
306
|
+
{"構造": "HCP", "r_th": 0.40, "n_cl": 8, "疲労限度": "△ 中間的", "例": "Ti, Mg, Zn"},
|
|
307
|
+
])
|
|
308
|
+
st.dataframe(preset_df, use_container_width=True)
|
|
309
|
+
|
|
310
|
+
st.markdown("""
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
### A_int / A_ext 分離
|
|
314
|
+
|
|
315
|
+
| パラメータ | 意味 | 導出方法 |
|
|
316
|
+
|-----------|------|---------|
|
|
317
|
+
| **r_th** | 疲労限度閾値 | 構造プリセット(BCC/FCC/HCP) |
|
|
318
|
+
| **n_cl** | Basquin指数 | 構造プリセット |
|
|
319
|
+
| **A_int** | 内部スケール | δパラメータから計算 |
|
|
320
|
+
| **A_ext** | 外部要因 | **1点校正のみ** |
|
|
321
|
+
|
|
322
|
+
**結果: フィッティングパラメータ = 0.5個(A_ext の1点校正だけ)**
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### Author
|
|
327
|
+
**飯泉真道 & 環**
|
|
328
|
+
Version 6.8 | 2026-01-31
|
|
329
|
+
""")
|
|
330
|
+
|
|
331
|
+
# Footer
|
|
332
|
+
st.divider()
|
|
333
|
+
st.markdown("""
|
|
334
|
+
<div style='text-align: center; color: gray;'>
|
|
335
|
+
δ理論 疲労予測システム v6.8 | Masamichi Iizumi & Tamaki | 2026
|
|
336
|
+
</div>
|
|
337
|
+
""", unsafe_allow_html=True)
|