(git:ed6f26b)
Loading...
Searching...
No Matches
grpp_nuclear_models.c
Go to the documentation of this file.
1/*----------------------------------------------------------------------------*/
2/* CP2K: A general program to perform molecular dynamics simulations */
3/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
4/* */
5/* SPDX-License-Identifier: MIT */
6/*----------------------------------------------------------------------------*/
7
8/*
9 * libgrpp - a library for the evaluation of integrals over
10 * generalized relativistic pseudopotentials.
11 *
12 * Copyright (C) 2021-2023 Alexander Oleynichenko
13 */
14
15#include "grpp_nuclear_models.h"
16#include "grpp_specfunc.h"
17#include <math.h>
18
19#ifndef M_PI
20#define M_PI 3.14159265358979323846
21#endif
22
23extern double libgrpp_fermi_model_Sk(int k, double x);
24
25extern double libgrpp_fermi_model_norm_factor(double c, double a);
26
27extern double libgrpp_fermi_bubble_model_norm_factor(double c, double a,
28 double k);
29
30/*
31 * estimates for root mean square radius of nuclear charge distribution
32 */
33
34/**
35 * estimate for R(rms) from:
36 * W. R. Johnson, G. Soff. The Lamb shift in hydrogen-like atoms, 1 <= Z <=>
37 * 110. At. Data Nucl. Data Tables, 33(3), 405 (1985).
38 *
39 * A = mass number
40 * returns R(rms) in [fm] units
41 */
43 return 0.836 * pow(A, 1.0 / 3.0) + 0.570;
44}
45
46/**
47 * estimate for R(rms) from:
48 * O. A. Golovko, I. A. Goidenko, I. I. Tupitsyn.
49 * Quantum electrodynamic corrections for valence electrons in Eka-Hg.
50 * Opt. Spectrosc. 104(5), 662 (2008).
51 *
52 * A = mass number
53 * returns R(rms) in [fm] units
54 */
56 return 0.77 * pow(A, 1.0 / 3.0) + 0.98;
57}
58
59/**
60 * estimate parameters of the Fermi model using default formulas for 'c' and
61 * 'a'. return -1 if such estimate cannot be performed, 1 otherwise.
62 *
63 * units: Fermi for R_rms, c, a.
64 */
65int libgrpp_estimate_fermi_model_parameters(double R_rms, double *c,
66 double *a) {
67 const double t = 2.3;
68 *a = t / (4 * log(3));
69
70 const double c2 =
71 5.0 / 3.0 * R_rms * R_rms - 7.0 / 3.0 * M_PI * M_PI * (*a) * (*a);
72 if (c2 < 0) {
73 return -1;
74 }
75
76 *c = sqrt(c2);
77 return 1;
78}
79
80/*
81 * radially-local electrostatic potentials and density functions
82 * for different nuclear finite charge distribution models
83 */
84
85/**
86 * point charge
87 */
88double libgrpp_coulomb_potential_point(double r, double Z) { return -Z / r; }
89
90/**
91 * uniformly charged ball: density
92 */
93double libgrpp_charge_density_ball(double r, double Z, double R_rms) {
94 const double R0 = sqrt(5.0 / 3.0) * R_rms;
95
96 if (r <= R0) {
97 return 3.0 * Z / (4.0 * M_PI * R0 * R0 * R0);
98 } else {
99 return 0.0;
100 }
101}
102
103/**
104 * uniformly charged ball: potential
105 *
106 * formula from:
107 * L. Visscher, K. G. Dyall,
108 * Dirac-Fock atomic electronic structure calculations using different nuclear
109 * charge distributions. Atomic Data and Nuclear Data Tables, 67, 207–224 (1997)
110 */
111double libgrpp_coulomb_potential_ball(double r, double Z, double R_rms) {
112 const double R0 = sqrt(5.0 / 3.0) * R_rms;
113
114 if (r <= R0) {
115 return -Z / (2.0 * R0) * (3.0 - r * r / (R0 * R0));
116 } else {
117 return -Z / r;
118 }
119}
120
121/**
122 * Gaussian charge distribution: density
123 */
124double libgrpp_charge_density_gaussian(double r, double Z, double R_rms) {
125 const double xi = 3.0 / (2.0 * R_rms * R_rms);
126 const double rho0 = Z * pow(xi / M_PI, 1.5);
127
128 return rho0 * exp(-xi * r * r);
129}
130
131/**
132 * Gaussian charge distribution: potential
133 *
134 * formula from:
135 * L. Visscher, K. G. Dyall,
136 * Dirac-Fock atomic electronic structure calculations using different nuclear
137 * charge distributions. Atomic Data and Nuclear Data Tables, 67, 207–224 (1997)
138 */
139double libgrpp_coulomb_potential_gaussian(double r, double Z, double R_rms) {
140 const double xi = 3.0 / (2.0 * R_rms * R_rms);
141
142 return -Z / r * erf(sqrt(xi) * r);
143}
144
145/**
146 * Fermi charge distribution: density
147 */
148double libgrpp_charge_density_fermi(double r, double Z, double c, double a) {
149 const double N = libgrpp_fermi_model_norm_factor(c, a);
150 const double c3 = c * c * c;
151 const double rho0 = 3.0 * Z / (4 * M_PI * c3 * N);
152
153 return rho0 / (1.0 + exp((r - c) / a));
154}
155
156/**
157 * Fermi charge distribution: rms radius
158 */
159double libgrpp_rms_radius_fermi(int Z, double c, double a) {
160 const double N = libgrpp_fermi_model_norm_factor(c, a);
161 const double c3 = c * c * c;
162 const double rho0 = 3.0 * Z / (4 * M_PI * c3 * N);
163
164 const double r2 =
165 4 * M_PI * rho0 / Z * pow(c, 5) / 5.0 *
166 (1.0 + 10.0 / 3.0 * a * a * M_PI * M_PI / (c * c) +
167 7.0 / 3.0 * pow(M_PI, 4) * pow(a, 4) / pow(c, 4) -
168 120.0 * pow(a, 5) / pow(c, 5) * libgrpp_specfunc_fermi_sk(5, -c / a));
169
170 return sqrt(r2);
171}
172
173/**
174 * Fermi charge distribution: potential
175 *
176 * formula from:
177 * N. S. Mosyagin, A. V. Zaitsevskii, A. V. Titov
178 * Generalized relativistic effective core potentials for superheavy elements
179 * Int. J. Quantum Chem. e26076 (2019)
180 * doi: https://doi.org/10.1002/qua.26076
181 */
182double libgrpp_coulomb_potential_fermi(double r, double Z, double c, double a) {
183 const double a2 = a * a;
184 const double a3 = a * a * a;
185 const double c3 = c * c * c;
186 const double N = libgrpp_fermi_model_norm_factor(c, a);
187
188 if (r > c) {
189 const double S2 = libgrpp_specfunc_fermi_sk(2, (c - r) / a);
190 const double S3 = libgrpp_specfunc_fermi_sk(3, (c - r) / a);
191
192 return -Z / (N * r) * (N + 3 * a2 * r / c3 * S2 + 6 * a3 / c3 * S3);
193 } else {
194 const double P2 = libgrpp_specfunc_fermi_sk(2, (r - c) / a);
195 const double P3 = libgrpp_specfunc_fermi_sk(3, (r - c) / a);
196 const double S3 = libgrpp_specfunc_fermi_sk(3, -c / a);
197 const double r3 = r * r * r;
198
199 return -Z / (N * r) *
200 (1.5 * r / c - r3 / (2 * c3) + M_PI * M_PI * a2 * r / (2 * c3) -
201 3 * a2 * r / c3 * P2 + 6 * a3 / c3 * (P3 - S3));
202 }
203}
204
205/**
206 * normalization factor for the Fermi nuclear charge distribution
207 */
208double libgrpp_fermi_model_norm_factor(double c, double a) {
209 const double a2 = a * a;
210 const double a3 = a * a * a;
211 const double c2 = c * c;
212 const double c3 = c * c * c;
213
214 return 1.0 + M_PI * M_PI * a2 / c2 -
215 6.0 * a3 / c3 * libgrpp_specfunc_fermi_sk(3, -c / a);
216}
217
218/**
219 * "Fermi bubble" charge distribution: density
220 */
221double libgrpp_charge_density_fermi_bubble(double r, double Z, double c,
222 double a, double k) {
223 const double Nk = libgrpp_fermi_bubble_model_norm_factor(c, a, k);
224 const double c3 = c * c * c;
225 const double rho0 = 3.0 * Z / (4 * M_PI * c3 * Nk);
226
227 return rho0 * (1 + k * pow(r / c, 2)) / (1.0 + exp((r - c) / a));
228}
229
230/**
231 * "Fermi bubble" charge distribution: rms radius
232 */
233double libgrpp_rms_radius_fermi_bubble(int Z, double c, double a, double k) {
234 const double Nk = libgrpp_fermi_bubble_model_norm_factor(c, a, k);
235 const double c3 = c * c * c;
236 const double rho0 = 3.0 * Z / (4 * M_PI * c3 * Nk);
237
238 const double part_r4 =
239 pow(c, 5) / 5.0 *
240 (1.0 + 10.0 / 3.0 * a * a * M_PI * M_PI / (c * c) +
241 7.0 / 3.0 * pow(M_PI, 4) * pow(a, 4) / pow(c, 4) -
242 120.0 * pow(a, 5) / pow(c, 5) * libgrpp_specfunc_fermi_sk(5, -c / a));
243
244 const double part_r6 =
245 pow(c, 7) / 7.0 *
246 (1.0 + 7.0 * a * a * M_PI * M_PI / (c * c) +
247 49.0 / 3.0 * pow(M_PI, 4) * pow(a, 4) / pow(c, 4) +
248 31.0 / 3.0 * pow(M_PI, 6) * pow(a, 6) / pow(c, 6) -
249 5040.0 * pow(a, 7) / pow(c, 7) * libgrpp_specfunc_fermi_sk(7, -c / a));
250
251 const double r2 = 4 * M_PI * rho0 / Z * (part_r4 + k / (c * c) * part_r6);
252
253 return sqrt(r2);
254}
255
256/**
257 * "Fermi bubble" charge distribution: potential.
258 *
259 * derivation of the formula is based on:
260 *
261 * F. A. Parpia and A. K. Mohanty,
262 * Relativistic basis-set calculations for atoms with Fermi nuclei.
263 * Phys. Rev. A 46, 3735 (1992)
264 * doi: 10.1103/PhysRevA.46.3735
265 *
266 */
267double libgrpp_coulomb_potential_fermi_bubble(double r, double Z, double c,
268 double a, double k) {
269 // const double a2 = a * a;
270 // const double a3 = a * a * a;
271 // const double c2 = c * c;
272 // const double c3 = c * c * c;
273
274 const double Nk = libgrpp_fermi_bubble_model_norm_factor(c, a, k);
275 // const double rho0 = 3 * Z / (4 * M_PI * M_PI * c * c * c * Nk);
276
277 double F0 = 0.0;
278 double F2 = 0.0;
279
280 if (r < c) {
281 const double S2 = libgrpp_specfunc_fermi_sk(2, (r - c) / a);
282 const double S3 = libgrpp_specfunc_fermi_sk(3, (r - c) / a);
283 const double S4 = libgrpp_specfunc_fermi_sk(4, (r - c) / a);
284 const double S5 = libgrpp_specfunc_fermi_sk(5, (r - c) / a);
285
286 // contribution from the "classical" Fermi term
287 F0 = -pow(r, 3) / 6.0 - r * a * a * S2 + 2.0 * pow(a, 3) * S3 +
288 r * c * c / 2.0 + M_PI * M_PI / 6.0 * r * a * a -
289 2.0 * pow(a, 3) * libgrpp_specfunc_fermi_sk(3, -c / a);
290
291 // contribution from the quadratic, "hole" term
292 F2 = -pow(r, 5) / 20.0 - pow(r, 3) * pow(a, 2) * S2 +
293 6.0 * pow(r, 2) * pow(a, 3) * S3 - 18.0 * r * pow(a, 4) * S4 +
294 24.0 * pow(a, 5) * S5 + r * pow(c, 4) / 4.0 +
295 r * M_PI * M_PI * c * c * a * a / 2.0 +
296 r * pow(a, 4) * pow(M_PI, 4) * 7.0 / 60.0 -
297 24.0 * pow(a, 5) * libgrpp_specfunc_fermi_sk(5, -c / a);
298 } else {
299 const double S2 = libgrpp_specfunc_fermi_sk(2, (c - r) / a);
300 const double S3 = libgrpp_specfunc_fermi_sk(3, (c - r) / a);
301 const double S4 = libgrpp_specfunc_fermi_sk(4, (c - r) / a);
302 const double S5 = libgrpp_specfunc_fermi_sk(5, (c - r) / a);
303
304 // contribution from the "classical" Fermi term
305 F0 = pow(c, 3) / 3.0 + M_PI * M_PI / 3.0 * c * a * a -
306 2.0 * pow(a, 3) * libgrpp_specfunc_fermi_sk(3, -c / a) +
307 r * a * a * S2 + 2.0 * pow(a, 3) * S3;
308
309 // contribution from the quadratic, "hole" term
310 F2 = pow(c, 5) / 5.0 + 2.0 * pow(c, 3) * a * a * M_PI * M_PI / 3.0 +
311 7.0 * pow(a, 4) * c * pow(M_PI, 4) / 15.0 -
312 24.0 * pow(a, 5) * libgrpp_specfunc_fermi_sk(5, -c / a) +
313 pow(a, 2) * pow(r, 3) * S2 + 6.0 * pow(a, 3) * pow(r, 2) * S3 +
314 18.0 * r * pow(a, 4) * S4 + 24.0 * pow(a, 5) * S5;
315 }
316
317 return -Z / (Nk * r) * 3.0 / pow(c, 3) * (F0 + k / (c * c) * F2);
318}
319
320/**
321 * normalization factor for the "Fermi bubble" nuclear charge distribution
322 */
323double libgrpp_fermi_bubble_model_norm_factor(double c, double a, double k) {
324 const double a2 = a * a;
325 const double a3 = a * a2;
326 const double a4 = a * a3;
327 const double a5 = a * a4;
328 const double c2 = c * c;
329 const double c3 = c * c2;
330 const double c4 = c * c3;
331 const double c5 = c * c4;
332
333 return libgrpp_fermi_model_norm_factor(c, a) + 3.0 / 5.0 * k +
334 2.0 * M_PI * M_PI * a2 * k / c2 +
335 7.0 * M_PI * M_PI * M_PI * M_PI * a4 * k / (5.0 * c4) -
336 72.0 * a5 * k / c5 * libgrpp_specfunc_fermi_sk(5, -c / a);
337}
double libgrpp_fermi_model_norm_factor(double c, double a)
double libgrpp_coulomb_potential_ball(double r, double Z, double R_rms)
double libgrpp_charge_density_fermi_bubble(double r, double Z, double c, double a, double k)
int libgrpp_estimate_fermi_model_parameters(double R_rms, double *c, double *a)
double libgrpp_coulomb_potential_gaussian(double r, double Z, double R_rms)
double libgrpp_rms_radius_fermi_bubble(int Z, double c, double a, double k)
double libgrpp_estimate_nuclear_rms_radius_golovko_2008(int A)
double libgrpp_coulomb_potential_point(double r, double Z)
double libgrpp_coulomb_potential_fermi_bubble(double r, double Z, double c, double a, double k)
double libgrpp_estimate_nuclear_rms_radius_johnson_1985(int A)
double libgrpp_charge_density_fermi(double r, double Z, double c, double a)
double libgrpp_coulomb_potential_fermi(double r, double Z, double c, double a)
double libgrpp_fermi_model_Sk(int k, double x)
double libgrpp_fermi_bubble_model_norm_factor(double c, double a, double k)
double libgrpp_rms_radius_fermi(int Z, double c, double a)
#define M_PI
double libgrpp_charge_density_gaussian(double r, double Z, double R_rms)
double libgrpp_charge_density_ball(double r, double Z, double R_rms)
double libgrpp_specfunc_fermi_sk(int k, double x)