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.
@@ -0,0 +1,422 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Universal Lindemann Law Validation
4
+ ===================================
5
+ δ_L = (√48 / Z) × √(k_B T_m / E_coh)
6
+
7
+ No fitting parameters. Pure topology + thermodynamics.
8
+
9
+ Author: Masamichi Iizumi / Miosync Inc.
10
+ """
11
+
12
+ import numpy as np
13
+ import matplotlib.pyplot as plt
14
+ from dataclasses import dataclass
15
+
16
+ # Physical constants
17
+ k_B = 8.617333262e-5 # eV/K (Boltzmann constant)
18
+
19
+ # Geometric constant
20
+ C_geom = np.sqrt(48) # = 4√3 ≈ 6.928 (FCC reference: 12²/3)
21
+
22
+
23
+ @dataclass
24
+ class Metal:
25
+ """Metal properties for Lindemann calculation"""
26
+ name: str
27
+ structure: str
28
+ Z: int # Coordination number
29
+ T_m: float # Melting temperature [K]
30
+ E_coh: float # Cohesive energy [eV]
31
+ r_nn: float # Nearest neighbor distance [Å]
32
+ delta_exp: float # Experimental Lindemann ratio
33
+
34
+
35
+ # =============================================================================
36
+ # Experimental Data (7 metals: BCC, FCC, HCP)
37
+ # =============================================================================
38
+ metals = [
39
+ Metal("Fe", "BCC", 8, 1811, 4.28, 2.48, 0.180),
40
+ Metal("W", "BCC", 8, 3695, 8.90, 2.74, 0.160),
41
+ Metal("Cu", "FCC", 12, 1357, 3.49, 2.56, 0.100),
42
+ Metal("Al", "FCC", 12, 933, 3.39, 2.86, 0.100),
43
+ Metal("Ni", "FCC", 12, 1728, 4.44, 2.49, 0.110),
44
+ Metal("Ti", "HCP", 12, 1941, 4.85, 2.95, 0.100),
45
+ Metal("Mg", "HCP", 12, 923, 1.51, 3.21, 0.117),
46
+ ]
47
+
48
+
49
+ def universal_lindemann(Z: int, T_m: float, E_coh: float) -> float:
50
+ """
51
+ Universal Lindemann Law (parameter-free)
52
+
53
+ δ_L = (√48 / Z) × √(k_B T_m / E_coh)
54
+
55
+ Args:
56
+ Z: Coordination number (8 for BCC, 12 for FCC/HCP)
57
+ T_m: Melting temperature [K]
58
+ E_coh: Cohesive energy [eV]
59
+
60
+ Returns:
61
+ Lindemann ratio δ_L (dimensionless)
62
+ """
63
+ return (C_geom / Z) * np.sqrt(k_B * T_m / E_coh)
64
+
65
+
66
+ def rms_displacement(delta_L: float, r_nn: float) -> float:
67
+ """
68
+ RMS atomic displacement at melting point
69
+
70
+ √<u²> = δ_L × r_nn
71
+
72
+ Args:
73
+ delta_L: Lindemann ratio
74
+ r_nn: Nearest neighbor distance [Å]
75
+
76
+ Returns:
77
+ RMS displacement [Å]
78
+ """
79
+ return delta_L * r_nn
80
+
81
+
82
+ def validate_all():
83
+ """Calculate and display results for all metals"""
84
+
85
+ print("=" * 80)
86
+ print("UNIVERSAL LINDEMANN LAW VALIDATION")
87
+ print("δ_L = (√48 / Z) × √(k_B T_m / E_coh)")
88
+ print("=" * 80)
89
+ print(f"\nGeometric constant: √48 = {C_geom:.4f} (= 12²/3, FCC reference)")
90
+ print(f"Boltzmann constant: k_B = {k_B:.6e} eV/K\n")
91
+
92
+ # Results storage
93
+ results = []
94
+
95
+ # Table header
96
+ print("-" * 80)
97
+ print(f"{'Metal':>6} {'Struct':>6} {'Z':>3} {'T_m[K]':>8} {'E_coh[eV]':>10} "
98
+ f"{'δ_exp':>7} {'δ_pred':>7} {'Err[%]':>8}")
99
+ print("-" * 80)
100
+
101
+ for m in metals:
102
+ # Calculate predicted Lindemann ratio
103
+ delta_pred = universal_lindemann(m.Z, m.T_m, m.E_coh)
104
+
105
+ # Calculate RMS displacement
106
+ rms_pred = rms_displacement(delta_pred, m.r_nn)
107
+ rms_exp = rms_displacement(m.delta_exp, m.r_nn)
108
+
109
+ # Error
110
+ error = (delta_pred - m.delta_exp) / m.delta_exp * 100
111
+
112
+ # Store results
113
+ results.append({
114
+ 'metal': m,
115
+ 'delta_pred': delta_pred,
116
+ 'rms_pred': rms_pred,
117
+ 'rms_exp': rms_exp,
118
+ 'error': error
119
+ })
120
+
121
+ print(f"{m.name:>6} {m.structure:>6} {m.Z:>3} {m.T_m:>8.0f} {m.E_coh:>10.2f} "
122
+ f"{m.delta_exp:>7.3f} {delta_pred:>7.3f} {error:>+8.1f}")
123
+
124
+ print("-" * 80)
125
+
126
+ # Statistics
127
+ errors = [abs(r['error']) for r in results]
128
+ mae = np.mean(errors)
129
+ rmse = np.sqrt(np.mean([e**2 for e in errors]))
130
+
131
+ delta_exp_arr = np.array([r['metal'].delta_exp for r in results])
132
+ delta_pred_arr = np.array([r['delta_pred'] for r in results])
133
+ correlation = np.corrcoef(delta_exp_arr, delta_pred_arr)[0, 1]
134
+
135
+ print(f"\nStatistics:")
136
+ print(f" Mean Absolute Error (MAE): {mae:.2f}%")
137
+ print(f" Root Mean Square Error: {rmse:.2f}%")
138
+ print(f" Correlation coefficient: {correlation:.4f}")
139
+
140
+ # RMS Displacement Table
141
+ print("\n" + "-" * 80)
142
+ print("RMS ATOMIC DISPLACEMENTS AT MELTING POINT")
143
+ print("-" * 80)
144
+ print(f"{'Metal':>6} {'r_nn[Å]':>8} {'RMS_exp[Å]':>12} {'RMS_pred[Å]':>12}")
145
+ print("-" * 80)
146
+
147
+ for r in results:
148
+ m = r['metal']
149
+ print(f"{m.name:>6} {m.r_nn:>8.2f} {r['rms_exp']:>12.3f} {r['rms_pred']:>12.3f}")
150
+
151
+ print("-" * 80)
152
+
153
+ # Structure-dependent analysis
154
+ print("\n" + "-" * 80)
155
+ print("STRUCTURE-DEPENDENT ANALYSIS")
156
+ print("-" * 80)
157
+
158
+ for struct in ["BCC", "FCC", "HCP"]:
159
+ struct_results = [r for r in results if r['metal'].structure == struct]
160
+ if struct_results:
161
+ Z = struct_results[0]['metal'].Z
162
+ avg_exp = np.mean([r['metal'].delta_exp for r in struct_results])
163
+ avg_pred = np.mean([r['delta_pred'] for r in struct_results])
164
+ struct_mae = np.mean([abs(r['error']) for r in struct_results])
165
+ cage_ratio = 12 / Z
166
+ print(f" {struct} (Z={Z}): δ_exp={avg_exp:.3f}, δ_pred={avg_pred:.3f}, "
167
+ f"MAE={struct_mae:.1f}%, Cage ratio (12/Z)={cage_ratio:.2f}")
168
+
169
+ return results
170
+
171
+
172
+ def create_figure(results):
173
+ """Create validation figure with 3 panels"""
174
+
175
+ fig, axes = plt.subplots(1, 3, figsize=(14, 4.5))
176
+
177
+ # Color scheme by structure
178
+ colors = {'BCC': '#E74C3C', 'FCC': '#3498DB', 'HCP': '#2ECC71'}
179
+ markers = {'BCC': 's', 'FCC': 'o', 'HCP': '^'}
180
+
181
+ # ==========================================================================
182
+ # Panel (a): Predicted vs Experimental δ_L
183
+ # ==========================================================================
184
+ ax1 = axes[0]
185
+
186
+ for r in results:
187
+ m = r['metal']
188
+ ax1.scatter(m.delta_exp, r['delta_pred'],
189
+ c=colors[m.structure], marker=markers[m.structure],
190
+ s=120, edgecolors='black', linewidths=0.5, zorder=5)
191
+ ax1.annotate(m.name, (m.delta_exp, r['delta_pred']),
192
+ xytext=(5, 5), textcoords='offset points', fontsize=9)
193
+
194
+ # Identity line
195
+ lims = [0.05, 0.20]
196
+ ax1.plot(lims, lims, 'k--', lw=1.5, label='Identity', zorder=1)
197
+
198
+ # ±10% bounds
199
+ ax1.fill_between(lims, [x*0.9 for x in lims], [x*1.1 for x in lims],
200
+ alpha=0.15, color='gray', label='±10%')
201
+
202
+ ax1.set_xlim(lims)
203
+ ax1.set_ylim(lims)
204
+ ax1.set_xlabel(r'Experimental $\delta_L$', fontsize=11)
205
+ ax1.set_ylabel(r'Predicted $\delta_L$', fontsize=11)
206
+ ax1.set_title('(a) Universal Lindemann Law Validation', fontsize=12)
207
+ ax1.set_aspect('equal')
208
+ ax1.legend(loc='lower right', fontsize=9)
209
+ ax1.grid(True, alpha=0.3)
210
+
211
+ # ==========================================================================
212
+ # Panel (b): Structure-dependent trends
213
+ # ==========================================================================
214
+ ax2 = axes[1]
215
+
216
+ x_positions = {'BCC': 0, 'FCC': 1, 'HCP': 2}
217
+
218
+ for struct in ['BCC', 'FCC', 'HCP']:
219
+ struct_results = [r for r in results if r['metal'].structure == struct]
220
+ x = x_positions[struct]
221
+
222
+ for i, r in enumerate(struct_results):
223
+ m = r['metal']
224
+ offset = (i - len(struct_results)/2 + 0.5) * 0.15
225
+
226
+ # Experimental (filled)
227
+ ax2.scatter(x + offset - 0.05, m.delta_exp,
228
+ c=colors[struct], marker=markers[struct],
229
+ s=100, edgecolors='black', linewidths=0.5)
230
+
231
+ # Predicted (open)
232
+ ax2.scatter(x + offset + 0.05, r['delta_pred'],
233
+ c='white', marker=markers[struct],
234
+ s=100, edgecolors=colors[struct], linewidths=2)
235
+
236
+ ax2.annotate(m.name, (x + offset, max(m.delta_exp, r['delta_pred']) + 0.005),
237
+ ha='center', fontsize=8)
238
+
239
+ # Predicted averages
240
+ for struct in ['BCC', 'FCC', 'HCP']:
241
+ struct_results = [r for r in results if r['metal'].structure == struct]
242
+ Z = struct_results[0]['metal'].Z
243
+ avg_pred = np.mean([r['delta_pred'] for r in struct_results])
244
+ x = x_positions[struct]
245
+ ax2.axhline(y=avg_pred, xmin=(x-0.3)/3+0.05, xmax=(x+0.3)/3+0.05,
246
+ color=colors[struct], linestyle='--', linewidth=2, alpha=0.7)
247
+
248
+ ax2.set_xticks([0, 1, 2])
249
+ ax2.set_xticklabels(['BCC\n(Z=8)', 'FCC\n(Z=12)', 'HCP\n(Z=12)'])
250
+ ax2.set_ylabel(r'Lindemann ratio $\delta_L$', fontsize=11)
251
+ ax2.set_title('(b) Structure Dependence', fontsize=12)
252
+ ax2.set_ylim([0.05, 0.22])
253
+ ax2.grid(True, alpha=0.3, axis='y')
254
+
255
+ # Legend for panel b
256
+ from matplotlib.lines import Line2D
257
+ legend_elements = [
258
+ Line2D([0], [0], marker='o', color='w', markerfacecolor='gray',
259
+ markersize=10, label='Experimental'),
260
+ Line2D([0], [0], marker='o', color='w', markerfacecolor='white',
261
+ markeredgecolor='gray', markeredgewidth=2, markersize=10, label='Predicted')
262
+ ]
263
+ ax2.legend(handles=legend_elements, loc='upper right', fontsize=9)
264
+
265
+ # ==========================================================================
266
+ # Panel (c): Energy ratio analysis
267
+ # ==========================================================================
268
+ ax3 = axes[2]
269
+
270
+ for r in results:
271
+ m = r['metal']
272
+ energy_ratio = np.sqrt(k_B * m.T_m / m.E_coh)
273
+
274
+ ax3.scatter(energy_ratio, m.delta_exp,
275
+ c=colors[m.structure], marker=markers[m.structure],
276
+ s=120, edgecolors='black', linewidths=0.5, zorder=5)
277
+ ax3.annotate(m.name, (energy_ratio, m.delta_exp),
278
+ xytext=(5, 5), textcoords='offset points', fontsize=9)
279
+
280
+ # Theoretical lines
281
+ x_range = np.linspace(0.05, 0.25, 100)
282
+
283
+ # BCC line (Z=8)
284
+ ax3.plot(x_range, (C_geom/8) * x_range,
285
+ color=colors['BCC'], linestyle='-', linewidth=2,
286
+ label=f'BCC: δ = {C_geom/8:.3f} × √(k_BT_m/E_coh)')
287
+
288
+ # FCC/HCP line (Z=12)
289
+ ax3.plot(x_range, (C_geom/12) * x_range,
290
+ color=colors['FCC'], linestyle='-', linewidth=2,
291
+ label=f'FCC/HCP: δ = {C_geom/12:.3f} × √(k_BT_m/E_coh)')
292
+
293
+ ax3.set_xlabel(r'$\sqrt{k_B T_m / E_{coh}}$', fontsize=11)
294
+ ax3.set_ylabel(r'Lindemann ratio $\delta_L$', fontsize=11)
295
+ ax3.set_title('(c) Energy Scaling', fontsize=12)
296
+ ax3.legend(loc='upper left', fontsize=8)
297
+ ax3.grid(True, alpha=0.3)
298
+ ax3.set_xlim([0.05, 0.22])
299
+ ax3.set_ylim([0.05, 0.22])
300
+
301
+ plt.tight_layout()
302
+
303
+ # Save figure
304
+ plt.savefig('/content/universal_lindemann_validation.png', dpi=150,
305
+ bbox_inches='tight', facecolor='white')
306
+ plt.savefig('/content/universal_lindemann_validation.pdf',
307
+ bbox_inches='tight', facecolor='white')
308
+
309
+ print("\nFigures saved:")
310
+ print(" - universal_lindemann_validation.png")
311
+ print(" - universal_lindemann_validation.pdf")
312
+
313
+ return fig
314
+
315
+
316
+ def print_latex_table(results):
317
+ """Generate LaTeX table for paper"""
318
+
319
+ print("\n" + "=" * 80)
320
+ print("LaTeX TABLE")
321
+ print("=" * 80)
322
+
323
+ print(r"""
324
+ \begin{table}[htbp]
325
+ \centering
326
+ \caption{Validation of the Universal Lindemann Law:
327
+ $\delta_L = \frac{\sqrt{48}}{Z}\sqrt{\frac{k_B T_m}{E_{coh}}}$.
328
+ No fitting parameters.}
329
+ \label{tab:universal_lindemann}
330
+ \begin{tabular}{lcccccccc}
331
+ \toprule
332
+ Metal & Structure & $Z$ & $T_m$ [K] & $E_{coh}$ [eV] & $r_{nn}$ [\AA] & $\delta_L^{exp}$ & $\delta_L^{pred}$ & Error [\%] \\
333
+ \midrule""")
334
+
335
+ for r in results:
336
+ m = r['metal']
337
+ error_str = f"+{r['error']:.1f}" if r['error'] > 0 else f"{r['error']:.1f}"
338
+ print(f"{m.name} & {m.structure} & {m.Z} & {m.T_m:.0f} & {m.E_coh:.2f} & "
339
+ f"{m.r_nn:.2f} & {m.delta_exp:.3f} & {r['delta_pred']:.3f} & {error_str} \\\\")
340
+
341
+ # Statistics
342
+ errors = [abs(r['error']) for r in results]
343
+ mae = np.mean(errors)
344
+
345
+ print(r"""\midrule
346
+ \multicolumn{9}{l}{\textbf{Mean Absolute Error (MAE): """ + f"{mae:.1f}" + r"""\%}} \\
347
+ \bottomrule
348
+ \end{tabular}
349
+ \end{table}
350
+ """)
351
+
352
+
353
+ def print_rms_latex_table(results):
354
+ """Generate LaTeX table for RMS displacements"""
355
+
356
+ print("\n" + "=" * 80)
357
+ print("LaTeX TABLE - RMS DISPLACEMENTS")
358
+ print("=" * 80)
359
+
360
+ print(r"""
361
+ \begin{table}[htbp]
362
+ \centering
363
+ \caption{RMS atomic displacements at the melting point.}
364
+ \label{tab:rms_displacement}
365
+ \begin{tabular}{lccccc}
366
+ \toprule
367
+ Metal & Structure & $r_{nn}$ [\AA] & $\sqrt{\langle u^2 \rangle}^{exp}$ [\AA] & $\sqrt{\langle u^2 \rangle}^{pred}$ [\AA] \\
368
+ \midrule""")
369
+
370
+ for r in results:
371
+ m = r['metal']
372
+ print(f"{m.name} & {m.structure} & {m.r_nn:.2f} & {r['rms_exp']:.3f} & {r['rms_pred']:.3f} \\\\")
373
+
374
+ print(r"""\bottomrule
375
+ \end{tabular}
376
+ \end{table}
377
+ """)
378
+
379
+
380
+ def main():
381
+ """Main execution"""
382
+
383
+ # Validate all metals
384
+ results = validate_all()
385
+
386
+ # Create figure
387
+ fig = create_figure(results)
388
+
389
+ # Print LaTeX tables
390
+ print_latex_table(results)
391
+ print_rms_latex_table(results)
392
+
393
+ # Summary
394
+ print("\n" + "=" * 80)
395
+ print("SUMMARY")
396
+ print("=" * 80)
397
+ print(f"""
398
+ Universal Lindemann Law:
399
+
400
+ δ_L = (√48 / Z) × √(k_B T_m / E_coh)
401
+ = ({C_geom:.3f} / Z) × √(k_B T_m / E_coh)
402
+
403
+ Physical meaning:
404
+ √48 = 12/√3 ≈ 6.928 : 3D FCC cage geometry (12²/3)
405
+ 1/Z : Topological cage size
406
+ √(k_B T_m / E_coh) : Energy ratio (thermal/cohesive)
407
+
408
+ Results:
409
+ - 7 metals validated (Fe, W, Cu, Al, Ni, Ti, Mg)
410
+ - 3 crystal structures (BCC, FCC, HCP)
411
+ - Mean Absolute Error: {np.mean([abs(r['error']) for r in results]):.1f}%
412
+ - Fitting parameters: ZERO
413
+
414
+ The Lindemann criterion is NOT an empirical rule—
415
+ it is a geometric identity arising from topological cage confinement.
416
+ """)
417
+
418
+ return results
419
+
420
+
421
+ if __name__ == "__main__":
422
+ results = main()
core/__init__.py ADDED
@@ -0,0 +1,35 @@
1
+ """
2
+ δ-Theory Core Library
3
+ =====================
4
+
5
+ Unified yield stress and fatigue life prediction based on geometric first principles.
6
+
7
+ Modules:
8
+ - unified_yield_fatigue_v6_9: Main yield + fatigue model (v6.9b)
9
+ - dbt_unified: Ductile-Brittle Transition Temperature prediction
10
+ - materials: Material database
11
+ """
12
+
13
+ from .unified_yield_fatigue_v6_9 import (
14
+ Material,
15
+ MATERIALS,
16
+ calc_sigma_y,
17
+ fatigue_life_const_amp,
18
+ generate_sn_curve,
19
+ yield_by_mode,
20
+ FATIGUE_CLASS_PRESET,
21
+ )
22
+
23
+ from .dbt_unified import (
24
+ DBTUnified,
25
+ DBTCore,
26
+ GrainSizeView,
27
+ TemperatureView,
28
+ SegregationView,
29
+ MATERIAL_FE,
30
+ )
31
+
32
+ from .materials import MaterialGPU
33
+
34
+ __version__ = "6.9.0"
35
+ __author__ = "Masamichi Iizumi & Tamaki"