RadCluster
Graph-based cluster dynamics for irradiated materials
Loading...
Searching...
No Matches
binding_energies.py
Go to the documentation of this file.
1"""
2binding_energies.py — Defect cluster binding energies for bcc Fe / EUROFER97.
3
4All equations and tables cite:
5 Ghoniem, N.M. (2026), "A Cluster Dynamics Model for Radiation Damage
6 Evolution in Ferritic-Martensitic Steels" (Rate_Equations.pdf).
7
8Conventions
9-----------
10- Vacancy cluster of size m (pure void): c_{m,0}
11- He-vacancy cluster: c_{m,ℓ} — m vacancies + ℓ He atoms
12- Interstitial cluster of size n: c_n
13- All energies in eV; lengths in m unless stated.
14"""
15
16import numpy as np
17
18_kB = 8.617333262e-5 # eV K^-1
19_J_eV = 6.241509074e18 # J → eV
20
21
22# ── Helper ────────────────────────────────────────────────────────────────────
23
24def atomic_radius(Omega):
25 """Wigner-Seitz radius r_0 = (3Ω/4π)^{1/3} [m]."""
26 return (3.0 * Omega / (4.0 * np.pi)) ** (1.0 / 3.0)
27
28
29def capture_radius(n, Omega):
30 """r_n = r_0 · n^{1/3} [m]. Eq. 86 (equivalent form)."""
31 return atomic_radius(Omega) * np.asarray(n, dtype=float) ** (1.0 / 3.0)
32
33
34# ── 1. Vacancy cluster (void) binding energies ───────────────────────────────
35
36# Atomistic fitting amplitudes A(m) for the void capillary correction.
37# Table 18 of Rate_Equations.pdf. Index = He content ℓ = 0..4 (pure void case).
38_A_void = {0: 1.2353, 1: 2.9064, 2: 3.4147, 3: 2.1504, 4: -0.1590} # eV
39_lambda_void = 0.5756 # decay constant [vac^-1], = ln(100)/8
40
41
42def E_b_void(m, E_f_v, gamma_s, Omega, lambda_void=None, A_void_0=None):
43 """
44 Binding energy of the m-th vacancy in a spherical void cluster.
45
46 Capillary formula with atomistic correction (Eqs. 66-67):
47 E_b(m) = E_f_v − A_cap · [m^{2/3} − (m−1)^{2/3}]
48 + A_void(0) · exp(−λ·(m−1)) [Eq. 67 correction]
49
50 where A_cap = 4π·γ_s·r_0² [eV], r_0 = (3Ω/4π)^{1/3}.
51
52 Special case m=1: return E_f_v (monomer formation energy).
53
54 Parameters
55 ----------
56 m : int or array
57 E_f_v : float [eV]
58 gamma_s : float [J/m²]
59 Omega : float [m³]
60 lambda_void : float or None [vac^-1]
61 Blend decay constant λ. ``None`` (default) uses the module constant
62 ``_lambda_void`` = ln(100)/8, preserving legacy behaviour. Supplied
63 from the ``dissociation`` sheet key ``lambda`` by ReactionRates so the
64 workbook value is actually honoured — before this argument existed the
65 workbook carried ``lambda`` and ``A_void_0`` but nothing read them.
66 A_void_0 : float or None [eV]
67 Atomistic correction amplitude A(0). ``None`` uses ``_A_void[0]``.
68
69 Returns
70 -------
71 E_b : float or array [eV]
72 """
73 r0 = atomic_radius(Omega)
74 A_cap = 4.0 * np.pi * gamma_s * r0**2 * _J_eV # eV — Eq. 66
75 A_atm = _A_void[0] if A_void_0 is None else float(A_void_0)
76 _lam = _lambda_void if lambda_void is None else float(lambda_void)
77
78 m = np.asarray(m, dtype=float)
79 capillary = A_cap * (m**(2.0/3.0) - (m - 1.0)**(2.0/3.0))
80 correction = A_atm * np.exp(-_lam * np.maximum(m - 1.0, 0.0))
81
82 Eb = np.where(m <= 1.0,
83 E_f_v,
84 E_f_v - capillary + correction)
85 return float(Eb) if Eb.ndim == 0 else Eb
86
87
88# ── 2. He–vacancy (bubble) binding energies ─────────────────────────────────
89
90# He virial EOS coefficients (Table 8, Eqs. 64-65)
91_B2 = 1.67e-29 # m^3/atom — 2nd virial coefficient
92_B3 = 1.84e-58 # m^6/atom^2 — 3rd virial coefficient
93
94
95def He_pressure(m, ell, Omega, T):
96 """
97 He pressure in a bubble with m vacancies and ℓ He atoms.
98 Virial EOS (Eq. 64):
99 P·V = N_He·k_B·T · [1 + B2·(N_He/V) + B3·(N_He/V)²]
100
101 V = m·Ω (bubble volume).
102
103 Returns
104 -------
105 P : float [Pa]
106 """
107 if ell <= 0:
108 return 0.0
109 V = float(m) * Omega
110 rho = float(ell) / V # He number density [m^-3]
111 kB_SI = _kB / _J_eV # eV/K → J/K
112 P = float(ell) * kB_SI * T / V * (1.0 + _B2 * rho + _B3 * rho**2)
113 return P
114
115
116def E_b_bubble(m, ell, E_f_v, gamma_s, Omega, T):
117 """
118 Effective vacancy binding energy for a He-vacancy bubble (m, ℓ).
119
120 Capillary model with He-pressure correction (Eqs. 70-73):
121 E_b_bub(m, ℓ) = E_f_v − A_cap·[m^{2/3}−(m−1)^{2/3}]
122 + P_He(m,ℓ)·Ω [He pressure work term]
123
124 The pressure term is POSITIVE: removing a vacancy from a gas-filled
125 cavity compresses the gas, costing work +P·Ω, so He raises the
126 vacancy binding energy and stabilizes bubbles against thermal
127 dissociation (equivalently c_v^eq(surface) ∝ exp[(2γ/r − P)Ω/kT]).
128 This term creates the stable-bubble branch and critical radius r*
129 of critical-bubble theory (Mansur & Coghlan).
130
131 Parameters
132 ----------
133 m : int
134 ell : int or float (can be fractional mean loading)
135 E_f_v : float [eV]
136 gamma_s : float [J/m²]
137 Omega : float [m³]
138 T : float [K]
139
140 Returns
141 -------
142 E_b : float [eV]
143 """
144 r0 = atomic_radius(Omega)
145 A_cap = 4.0 * np.pi * gamma_s * r0**2 * _J_eV
146 m_f = float(m)
147 capillary = A_cap * (m_f**(2.0/3.0) - max(m_f - 1.0, 0.0)**(2.0/3.0))
148 P = He_pressure(m, ell, Omega, T)
149 dE_P = P * Omega * _J_eV # Pa·m³ → eV
150 return E_f_v - capillary + dE_P
151
152
153# ── 3. He binding energy to bubbles ─────────────────────────────────────────
154
155# Atomistic fitting amplitudes A^He(α) for ℓ ≤ α.
156# Table 19 of Rate_Equations.pdf.
157_A_He = {2: 0.55, 3: 0.40, 4: 0.75} # eV
158_mu_He = 0.658 # decay constant [He^-1]
159
160def E_b_He(m, ell, E_s_He, Omega, T, B2=_B2, B3=_B3):
161 """
162 He binding energy: energy to remove one He from bubble (m, ℓ).
163
164 Combined continuum + atomistic formula (Eqs. 76-77, Table 19):
165
166 E_b^He(m, ℓ) = E_s^He + P_He(m,ℓ)·Ω [continuum, Eq. 76]
167 + f_blend · A^He(α) · exp(−μ·(ℓ−α)) [atomistic, Eq. 77]
168
169 where α = ℓ_max(m) = floor(alpha_He · m^{2/3}) is the trap-mutation limit,
170 and f_blend fades the atomistic correction for large ℓ.
171
172 Parameters
173 ----------
174 m : int
175 ell : int — current He content
176 E_s_He : float [eV] — He interstitial solution energy (= 2.35 eV, Table 5)
177 Omega : float [m³]
178 T : float [K]
179
180 Returns
181 -------
182 E_b : float [eV]
183 """
184 P = He_pressure(m, ell, Omega, T)
185 E_cont = E_s_He + P * Omega * _J_eV # continuum term
186
187 # atomistic correction for small ℓ
188 alpha = int(round(ell)) # closest integer loading
189 A_atm = _A_He.get(alpha, 0.0)
190 if A_atm != 0.0:
191 E_atm = A_atm * np.exp(-_mu_He * max(ell - alpha, 0.0))
192 else:
193 E_atm = 0.0
194
195 return E_cont + E_atm
196
197
198def E_b_He_first(E_b_hV_1=2.30):
199 """He binding energy to a monovacancy (first He, Table 5). Eq. 76."""
200 return E_b_hV_1
201
202
203def E_b_He_second(E_b_hV_2=2.00):
204 """He binding energy to a monovacancy (second He, Table 5). Eq. 76."""
205 return E_b_hV_2
206
207
208# ── 4. Interstitial loop binding energies ────────────────────────────────────
209
210def _E_b_loop_i_continuum(n, E_f_i=3.77, G_shear=82e9, b=2.49e-10,
211 nu=0.29, gamma_sf=0.6, Omega=1.18e-29):
212 """
213 Continuum binding energy of the n-th SIA to an interstitial loop.
214
215 E_b^{i,cont}(n) = E_f^i − μ_loop^{(i)}(n) [Eqs. i_binding, chem_pot_i_loop]
216
217 where μ = Gb·Ω/(4π(1−ν)R)·[ln(R/r_c)+1] + γ_sf·Ω/b,
218 R = sqrt(n·Ω/(π·b)), r_c = b/3.
219 """
220 n = np.asarray(n, dtype=float)
221 n_safe = np.maximum(n, 2.0)
222 r_c = b / 3.0
223 R = np.sqrt(n_safe * Omega / (np.pi * b))
224 ln_fac = np.log(R / r_c) + 1.0
225 mu = (G_shear * b * Omega / (4.0 * np.pi * (1.0 - nu) * R)) * ln_fac \
226 + gamma_sf * Omega / b
227 mu_eV = mu * _J_eV
228 Eb = E_f_i - mu_eV
229 return Eb
230
231
232def A_111_from_E_b_i2(E_b_i2, B_111):
233 """
234 Loop-binding amplitude ``A_111`` implied by a measured **di-interstitial
235 binding energy** ``E_b^i(2)``.
236
237 The small-n branch of :func:`E_b_loop_i` is the DFT power-law fit
238 ``E_b^fit(n) = A_111 · n^{+B_111}`` (note the exponent is POSITIVE — binding
239 *increases* with loop size). Evaluated at n = 2 this is the binding of the
240 second SIA to a mono-interstitial, i.e. the di-interstitial binding energy.
241 Inverting,
242
243 A_111 = E_b^i(2) · 2^{−B_111}
244
245 Anchoring on ``E_b^i(2)`` rather than on ``A_111`` directly is preferable
246 for calibration: ``A_111`` has no independent measurement, whereas
247 ``E_b^i(2)`` is reported by DFT for bcc Fe (≈0.8 eV).
248
249 Note that :func:`E_b_loop_i` returns the *blended* value at n = 2, which
250 differs from ``E_b_i2`` by the continuum admixture (1 − w) ≈ 1e-4 at the
251 default blend (n_tr = 25, σ_tr = 5) — negligible, but not identically zero.
252
253 Parameters
254 ----------
255 E_b_i2 : float [eV] — di-interstitial binding energy
256 B_111 : float — power-law exponent
257
258 Returns
259 -------
260 A_111 : float [eV]
261 """
262 return float(E_b_i2) * 2.0 ** (-float(B_111))
263
264
265def E_b_loop_i(n, A_111=0.7501, B_111=0.3873, A_100=0.7160, B_100=0.3581,
266 n_tr=25.0, sigma_tr=5.0,
267 E_f_i=3.77, G_shear=82e9, b_111=2.49e-10, nu=0.29,
268 gamma_sf=0.6, Omega=1.18e-29):
269 """
270 Binding energy of the n-th SIA to an interstitial loop of size n−1.
271
272 Small-n DFT fit blended to continuum limit (Eqs. Eb_smalln_fit, Eb_blended):
273 E_b^fit(n) = A · n^{+B} [Eq. Eb_smalln_fit]
274 E_b^cont(n) = E_f^i − μ_loop(n) [continuum elasticity]
275 w(n) = 0.5·(1 + tanh((n_tr − n)/σ_tr)) [Eq. weight_function]
276 E_b(n) = w·E_b^fit + (1−w)·E_b^cont [Eq. Eb_blended]
277
278 For small n, w→1 and E_b follows the DFT power-law fit.
279 For large n, w→0 and E_b approaches E_f^i (formation energy).
280
281 Parameters
282 ----------
283 n : int or array (≥ 2)
284 A_111, B_111 : float — ½⟨111⟩ loop fit (Table 18)
285 A_100, B_100 : float — ⟨100⟩ loop fit (Table 18)
286 n_tr : float — blend center (25 SIAs)
287 sigma_tr : float — blend width (5 SIAs)
288 E_f_i : float — SIA formation energy [eV]
289 G_shear : float — shear modulus [Pa]
290 b_111 : float — ½⟨111⟩ Burgers vector [m]
291 nu : float — Poisson ratio
292 gamma_sf : float — stacking fault energy [J/m²]
293 Omega : float — atomic volume [m³]
294
295 Returns
296 -------
297 E_b : float or array [eV]
298 """
299 n = np.asarray(n, dtype=float)
300 n_safe = np.maximum(n, 2.0)
301
302 # Small-n DFT power-law fit (exponent is POSITIVE: E_b increases with n)
303 Eb_fit = A_111 * n_safe**(B_111)
304
305 # Large-n continuum elasticity
306 Eb_cont = _E_b_loop_i_continuum(n_safe, E_f_i, G_shear, b_111,
307 nu, gamma_sf, Omega)
308
309 # Smooth blend: w→1 for small n (DFT regime), w→0 for large n (continuum)
310 w = 0.5 * (1.0 + np.tanh((n_tr - n_safe) / sigma_tr))
311 Eb = w * Eb_fit + (1.0 - w) * Eb_cont
312
313 return float(Eb) if Eb.ndim == 0 else Eb
314
315
316def E_b_loop_100(n, A_100=0.7160, B_100=0.3581,
317 n_tr=25.0, sigma_tr=5.0,
318 E_f_i=3.77, G_shear=82e9, b_100=2.8665e-10, nu=0.29,
319 gamma_sf=0.6, Omega=1.18e-29):
320 """
321 Binding energy of the n-th SIA to a ⟨100⟩ interstitial loop of size n−1.
322
323 Sibling of :func:`E_b_loop_i` for the sessile ⟨100⟩ population
324 (½⟨111⟩→⟨100⟩ loop-conversion work). Same small-n DFT fit blended to the
325 continuum limit (Eqs. Eb_smalln_fit, Eb_blended), but with the ⟨100⟩ fit
326 amplitudes ``A_100, B_100`` (Table 18 — already carried, dormant, by
327 :func:`E_b_loop_i`) and the ⟨100⟩ Burgers vector ``b_100 = a`` in the
328 continuum tail.
329
330 E_b^fit(n) = A_100 · n^{+B_100}
331 E_b^cont(n) = E_f^i − μ_loop(n; b_100)
332 w(n) = 0.5·(1 + tanh((n_tr − n)/σ_tr))
333 E_b(n) = w·E_b^fit + (1−w)·E_b^cont
334
335 ⟨100⟩ loops are slightly less bound than ½⟨111⟩ at small n
336 (``A_100 < A_111``); emission is therefore slow but nonzero, feeding the
337 ⟨100⟩ ``DISSOCIATION`` edge.
338
339 Parameters mirror :func:`E_b_loop_i`; ``b_100`` defaults to the bcc-Fe
340 lattice parameter ``a = 2.8665 Å`` (= ⟨100⟩ Burgers vector magnitude).
341 """
342 n = np.asarray(n, dtype=float)
343 n_safe = np.maximum(n, 2.0)
344 Eb_fit = A_100 * n_safe**(B_100)
345 Eb_cont = _E_b_loop_i_continuum(n_safe, E_f_i, G_shear, b_100,
346 nu, gamma_sf, Omega)
347 w = 0.5 * (1.0 + np.tanh((n_tr - n_safe) / sigma_tr))
348 Eb = w * Eb_fit + (1.0 - w) * Eb_cont
349 return float(Eb) if Eb.ndim == 0 else Eb
350
351
352def E_b_loop_v(m, E_f_v, gamma_sf, Omega, b_111):
353 """
354 Vacancy loop binding energy (Eqs. 104-105).
355
356 Continuum (Frank loop) with DFT anchor at m=2:
357 E_b^vloop(m) = E_f_v − A_sf · [m^{1/2} − (m−1)^{1/2}]
358
359 where A_sf = 2·b_111 · sqrt(π·γ_sf·Ω/√3) · _J_eV.
360
361 Parameters
362 ----------
363 m : int or array (≥ 1)
364 E_f_v : float [eV]
365 gamma_sf: float [J/m²] — stacking fault energy
366 Omega : float [m³]
367 b_111 : float [m] — ½⟨111⟩ Burgers vector
368
369 Returns
370 -------
371 E_b : float or array [eV]
372 """
373 A_sf = 2.0 * b_111 * np.sqrt(np.pi * gamma_sf * Omega / np.sqrt(3.0)) * _J_eV
374 m = np.asarray(m, dtype=float)
375 Eb = np.where(
376 m <= 1.0,
377 E_f_v,
378 E_f_v - A_sf * (m**(1.0/2.0) - (m - 1.0)**(1.0/2.0))
379 )
380 return float(Eb) if Eb.ndim == 0 else Eb
381
382
383# ── 5. Trap mutation barrier ─────────────────────────────────────────────────
384
385# Table 27 of Rate_Equations.pdf
386# Key: (m, ℓ) — (vacancies, He atoms)
387_E_TM_table = {
388 (1, 5): 1.00, # He5V1 — Morishita 2003
389 (1, 6): 0.50, # He6V1 — Morishita 2003
390 (1, 7): 0.00, # He7V1 — spontaneous (Gao 2011)
391 (0, 4): 0.30, # He4 self-trapping (Gao 2011)
392 (0, 5): 0.10, # He5 self-trapping (Gao 2011)
393 (0, 6): 0.00, # He6 spontaneous (Gao 2011)
394}
395
396
397def E_TM(m, ell, default=1e10):
398 """
399 Trap mutation barrier (Table 27, Eq. 83).
400
401 Returns the barrier E_TM(m, ℓ) [eV].
402 If (m, ℓ) not in the table, returns `default` (effectively disables TM).
403
404 Parameters
405 ----------
406 m : int — vacancies
407 ell : int — He atoms
408 default : float [eV] — barrier for unknown (m, ℓ)
409 """
410 return _E_TM_table.get((int(m), int(ell)), default)
411
412
413def Gamma_TM(m, ell, T, nu0_TM=1e12):
414 """
415 Trap mutation rate from bubble (m, ℓ) → (m+1, ℓ-1) [s^-1].
416
417 Γ_TM(m, ℓ) = ν_0_TM · exp(−E_TM(m,ℓ) / k_B T) (Eq. 142)
418
419 Parameters
420 ----------
421 m, ell : int
422 T : float [K]
423 nu0_TM : float [s^-1] — attempt frequency (Table 27)
424 """
425 E = E_TM(m, ell)
426 if E >= 1e9:
427 return 0.0
428 return nu0_TM * np.exp(-E / (_kB * T))
429
430
431# ── 6. Radiation re-solution rate ───────────────────────────────────────────
432
433def Gamma_res(ell, phi_dot, b0):
434 """
435 Radiation re-solution rate for He from bubble (m, ℓ) [s^-1].
436
437 Γ_res(m, ℓ) = b_0 · ℓ · φ̇ (Eq. 143)
438
439 Parameters
440 ----------
441 ell : int or float — He content
442 phi_dot : float [dpa/s] — displacement rate
443 b0 : float [dpa^-1 He^-1] — re-solution parameter (Table 29)
444 """
445 return b0 * float(ell) * phi_dot
446
447
448# ── 7. Maximum He loading per vacancy cluster ────────────────────────────────
449
450def ell_max(m, alpha_He=1.7):
451 """
452 Maximum He loading for cluster with m vacancies.
453 Trap-mutation limit: ℓ_max = floor(alpha_He · m^{2/3}). Table 29.
454 """
455 return int(np.floor(alpha_He * float(m)**(2.0 / 3.0)))
He_pressure(m, ell, Omega, T)
E_TM(m, ell, default=1e10)
E_b_He(m, ell, E_s_He, Omega, T, B2=_B2, B3=_B3)
_E_b_loop_i_continuum(n, E_f_i=3.77, G_shear=82e9, b=2.49e-10, nu=0.29, gamma_sf=0.6, Omega=1.18e-29)