Created
October 15, 2023 13:50
-
-
Save Ionizing/9cd263f2cdba6c5200387a07b1e85a03 to your computer and use it in GitHub Desktop.
First order and second order coulomb correction for PAW method, extracted from GPAW.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import gzip | |
from xml.etree import ElementTree as ET | |
from glob import glob | |
import numpy as np | |
import numpy.typing as npt | |
""" | |
All the functions ended with | |
- RETURN -> finished function | |
- PASS -> work in progress function | |
All the referred equations are in the paper | |
"The Projector Augmented-wave Method" | |
https://arxiv.org/pdf/0910.1921.pdf | |
""" | |
HARTREE = 27.211386024367243 | |
class Gaunt: | |
def __init__(self): | |
self.set_g() | |
self.set_YL() | |
return | |
def __call__(self, lmax: int = 2) -> npt.NDArray: | |
r'''Gaunt coefficients | |
::: | |
^ ^ -- L ^ | |
Y (r) Y (r) = > G Y (r) | |
L L -- L L L | |
1 2 L 1 2 | |
Copied from gpaw/gaunt.py L13-45 | |
''' | |
if not hasattr(self, 'gaunt_dict'): | |
self.gaunt_dict = {} | |
if lmax in self.gaunt_dict: | |
return self.gaunt_dict[lmax] | |
Lmax = ( lmax + 1) ** 2 | |
L2max = (2*lmax + 1) ** 2 | |
G_LLL = np.zeros((Lmax, L2max, L2max)) | |
for L1 in range(Lmax): | |
for L2 in range(L2max): | |
for L in range(L2max): | |
r = 0.0 | |
for c1, n1 in self.YL[L1]: | |
for c2, n2 in self.YL[L2]: | |
for c, n in self.YL[L]: | |
nx = n1[0] + n2[0] + n[0] | |
ny = n1[1] + n2[1] + n[1] | |
nz = n1[2] + n2[2] + n[2] | |
r += c * c1 * c2 * self.gam(nx, ny, nz) | |
G_LLL[L1, L2, L] = r | |
self.gaunt_dict[lmax] = G_LLL | |
return G_LLL | |
def set_g(self) -> None: | |
''' | |
Copied from gpaw/spherical_harmonics.py L69-L71 | |
''' | |
LMAX = 10 | |
g = [1.0] * LMAX | |
for l in range(1, LMAX): | |
g[l] = g[l-1] * (l - 0.5) | |
self.g = g | |
return | |
def gam(self, n0: int, n1: int, n2: int) -> float: | |
if (n0 % 2 != 0 | |
or n1 % 2 != 0 | |
or n2 % 2 != 0): | |
return 0.0 | |
h0 = n0 // 2 | |
h1 = n1 // 2 | |
h2 = n2 // 2 | |
return (2.0 * np.pi | |
* self.g[h0] * self.g[h1] * self.g[h2] | |
/ self.g[1 + h0 + h1 + h2]) | |
def set_YL(self) -> None: | |
''' | |
# Computer generated table - do not touch! | |
# The numbers match those in c/bmgs/spherical_harmonics.c and were | |
# originally generated with c/bmgs/sharmonic.py (old Python 2 code). | |
Copied from gpaw/spherical_harmonics.py | |
''' | |
YL = [ | |
# s, l=0: | |
[(0.28209479177387814, (0, 0, 0))], | |
# p, l=1: | |
[(0.4886025119029199, (0, 1, 0))], | |
[(0.4886025119029199, (0, 0, 1))], | |
[(0.4886025119029199, (1, 0, 0))], | |
# d, l=2: | |
[(1.0925484305920792, (1, 1, 0))], | |
[(1.0925484305920792, (0, 1, 1))], | |
[(0.6307831305050401, (0, 0, 2)), | |
(-0.31539156525252005, (0, 2, 0)), | |
(-0.31539156525252005, (2, 0, 0))], | |
[(1.0925484305920792, (1, 0, 1))], | |
[(0.5462742152960396, (2, 0, 0)), | |
(-0.5462742152960396, (0, 2, 0))], | |
# f, l=3: | |
[(-0.5900435899266435, (0, 3, 0)), | |
(1.7701307697799304, (2, 1, 0))], | |
[(2.890611442640554, (1, 1, 1))], | |
[(-0.4570457994644658, (0, 3, 0)), | |
(1.828183197857863, (0, 1, 2)), | |
(-0.4570457994644658, (2, 1, 0))], | |
[(0.7463526651802308, (0, 0, 3)), | |
(-1.1195289977703462, (2, 0, 1)), | |
(-1.1195289977703462, (0, 2, 1))], | |
[(1.828183197857863, (1, 0, 2)), | |
(-0.4570457994644658, (3, 0, 0)), | |
(-0.4570457994644658, (1, 2, 0))], | |
[(1.445305721320277, (2, 0, 1)), | |
(-1.445305721320277, (0, 2, 1))], | |
[(0.5900435899266435, (3, 0, 0)), | |
(-1.7701307697799304, (1, 2, 0))], | |
# g, l=4: | |
[(2.5033429417967046, (3, 1, 0)), | |
(-2.5033429417967046, (1, 3, 0))], | |
[(-1.7701307697799307, (0, 3, 1)), | |
(5.310392309339792, (2, 1, 1))], | |
[(-0.9461746957575601, (3, 1, 0)), | |
(-0.9461746957575601, (1, 3, 0)), | |
(5.6770481745453605, (1, 1, 2))], | |
[(-2.0071396306718676, (2, 1, 1)), | |
(2.676186174229157, (0, 1, 3)), | |
(-2.0071396306718676, (0, 3, 1))], | |
[(0.6347132814912259, (2, 2, 0)), | |
(-2.5388531259649034, (2, 0, 2)), | |
(0.31735664074561293, (0, 4, 0)), | |
(-2.5388531259649034, (0, 2, 2)), | |
(0.31735664074561293, (4, 0, 0)), | |
(0.8462843753216345, (0, 0, 4))], | |
[(2.676186174229157, (1, 0, 3)), | |
(-2.0071396306718676, (3, 0, 1)), | |
(-2.0071396306718676, (1, 2, 1))], | |
[(2.8385240872726802, (2, 0, 2)), | |
(0.47308734787878004, (0, 4, 0)), | |
(-0.47308734787878004, (4, 0, 0)), | |
(-2.8385240872726802, (0, 2, 2))], | |
[(1.7701307697799307, (3, 0, 1)), | |
(-5.310392309339792, (1, 2, 1))], | |
[(-3.755014412695057, (2, 2, 0)), | |
(0.6258357354491761, (0, 4, 0)), | |
(0.6258357354491761, (4, 0, 0))], | |
# h, l=5: | |
[(-6.5638205684017015, (2, 3, 0)), | |
(3.2819102842008507, (4, 1, 0)), | |
(0.6563820568401701, (0, 5, 0))], | |
[(8.302649259524165, (3, 1, 1)), | |
(-8.302649259524165, (1, 3, 1))], | |
[(-3.913906395482003, (0, 3, 2)), | |
(0.4892382994352504, (0, 5, 0)), | |
(-1.467714898305751, (4, 1, 0)), | |
(-0.9784765988705008, (2, 3, 0)), | |
(11.741719186446009, (2, 1, 2))], | |
[(-4.793536784973324, (3, 1, 1)), | |
(-4.793536784973324, (1, 3, 1)), | |
(9.587073569946648, (1, 1, 3))], | |
[(-5.435359814348363, (0, 3, 2)), | |
(0.9058933023913939, (2, 3, 0)), | |
(-5.435359814348363, (2, 1, 2)), | |
(3.6235732095655755, (0, 1, 4)), | |
(0.45294665119569694, (4, 1, 0)), | |
(0.45294665119569694, (0, 5, 0))], | |
[(3.508509673602708, (2, 2, 1)), | |
(-4.678012898136944, (0, 2, 3)), | |
(1.754254836801354, (0, 4, 1)), | |
(-4.678012898136944, (2, 0, 3)), | |
(1.754254836801354, (4, 0, 1)), | |
(0.9356025796273888, (0, 0, 5))], | |
[(-5.435359814348363, (3, 0, 2)), | |
(3.6235732095655755, (1, 0, 4)), | |
(0.45294665119569694, (5, 0, 0)), | |
(0.9058933023913939, (3, 2, 0)), | |
(-5.435359814348363, (1, 2, 2)), | |
(0.45294665119569694, (1, 4, 0))], | |
[(-2.396768392486662, (4, 0, 1)), | |
(2.396768392486662, (0, 4, 1)), | |
(4.793536784973324, (2, 0, 3)), | |
(-4.793536784973324, (0, 2, 3))], | |
[(3.913906395482003, (3, 0, 2)), | |
(-0.4892382994352504, (5, 0, 0)), | |
(0.9784765988705008, (3, 2, 0)), | |
(-11.741719186446009, (1, 2, 2)), | |
(1.467714898305751, (1, 4, 0))], | |
[(2.075662314881041, (4, 0, 1)), | |
(-12.453973889286246, (2, 2, 1)), | |
(2.075662314881041, (0, 4, 1))], | |
[(-6.5638205684017015, (3, 2, 0)), | |
(0.6563820568401701, (5, 0, 0)), | |
(3.2819102842008507, (1, 4, 0))], | |
# i, l=6: | |
[(4.099104631151485, (5, 1, 0)), | |
(-13.663682103838287, (3, 3, 0)), | |
(4.099104631151485, (1, 5, 0))], | |
[(11.83309581115876, (4, 1, 1)), | |
(-23.66619162231752, (2, 3, 1)), | |
(2.366619162231752, (0, 5, 1))], | |
[(20.182596029148968, (3, 1, 2)), | |
(-2.0182596029148967, (5, 1, 0)), | |
(2.0182596029148967, (1, 5, 0)), | |
(-20.182596029148968, (1, 3, 2))], | |
[(-7.369642076119388, (0, 3, 3)), | |
(-5.527231557089541, (2, 3, 1)), | |
(2.7636157785447706, (0, 5, 1)), | |
(22.108926228358165, (2, 1, 3)), | |
(-8.29084733563431, (4, 1, 1))], | |
[(-14.739284152238776, (3, 1, 2)), | |
(14.739284152238776, (1, 1, 4)), | |
(1.842410519029847, (3, 3, 0)), | |
(0.9212052595149235, (5, 1, 0)), | |
(-14.739284152238776, (1, 3, 2)), | |
(0.9212052595149235, (1, 5, 0))], | |
[(2.9131068125936572, (0, 5, 1)), | |
(-11.652427250374629, (0, 3, 3)), | |
(5.8262136251873144, (2, 3, 1)), | |
(-11.652427250374629, (2, 1, 3)), | |
(2.9131068125936572, (4, 1, 1)), | |
(4.660970900149851, (0, 1, 5))], | |
[(5.721228204086558, (4, 0, 2)), | |
(-7.628304272115411, (0, 2, 4)), | |
(-0.9535380340144264, (2, 4, 0)), | |
(1.0171072362820548, (0, 0, 6)), | |
(-0.9535380340144264, (4, 2, 0)), | |
(5.721228204086558, (0, 4, 2)), | |
(-0.3178460113381421, (0, 6, 0)), | |
(-7.628304272115411, (2, 0, 4)), | |
(-0.3178460113381421, (6, 0, 0)), | |
(11.442456408173117, (2, 2, 2))], | |
[(-11.652427250374629, (3, 0, 3)), | |
(4.660970900149851, (1, 0, 5)), | |
(2.9131068125936572, (5, 0, 1)), | |
(5.8262136251873144, (3, 2, 1)), | |
(-11.652427250374629, (1, 2, 3)), | |
(2.9131068125936572, (1, 4, 1))], | |
[(7.369642076119388, (2, 0, 4)), | |
(-7.369642076119388, (0, 2, 4)), | |
(-0.46060262975746175, (2, 4, 0)), | |
(-7.369642076119388, (4, 0, 2)), | |
(0.46060262975746175, (4, 2, 0)), | |
(-0.46060262975746175, (0, 6, 0)), | |
(0.46060262975746175, (6, 0, 0)), | |
(7.369642076119388, (0, 4, 2))], | |
[(7.369642076119388, (3, 0, 3)), | |
(-2.7636157785447706, (5, 0, 1)), | |
(5.527231557089541, (3, 2, 1)), | |
(-22.108926228358165, (1, 2, 3)), | |
(8.29084733563431, (1, 4, 1))], | |
[(2.522824503643621, (4, 2, 0)), | |
(5.045649007287242, (0, 4, 2)), | |
(-30.273894043723452, (2, 2, 2)), | |
(-0.5045649007287242, (0, 6, 0)), | |
(-0.5045649007287242, (6, 0, 0)), | |
(5.045649007287242, (4, 0, 2)), | |
(2.522824503643621, (2, 4, 0))], | |
[(2.366619162231752, (5, 0, 1)), | |
(-23.66619162231752, (3, 2, 1)), | |
(11.83309581115876, (1, 4, 1))], | |
[(-10.247761577878714, (4, 2, 0)), | |
(-0.6831841051919143, (0, 6, 0)), | |
(0.6831841051919143, (6, 0, 0)), | |
(10.247761577878714, (2, 4, 0))], | |
# j, l=7: | |
[(14.850417383016522, (2, 5, 0)), | |
(4.950139127672174, (6, 1, 0)), | |
(-24.75069563836087, (4, 3, 0)), | |
(-0.7071627325245963, (0, 7, 0))], | |
[(-52.91921323603801, (3, 3, 1)), | |
(15.875763970811402, (1, 5, 1)), | |
(15.875763970811402, (5, 1, 1))], | |
[(-2.5945778936013015, (6, 1, 0)), | |
(2.5945778936013015, (4, 3, 0)), | |
(-62.26986944643124, (2, 3, 2)), | |
(4.670240208482342, (2, 5, 0)), | |
(6.226986944643123, (0, 5, 2)), | |
(31.13493472321562, (4, 1, 2)), | |
(-0.5189155787202603, (0, 7, 0))], | |
[(41.513246297620825, (3, 1, 3)), | |
(12.453973889286246, (1, 5, 1)), | |
(-41.513246297620825, (1, 3, 3)), | |
(-12.453973889286246, (5, 1, 1))], | |
[(-18.775072063475285, (2, 3, 2)), | |
(-0.4693768015868821, (0, 7, 0)), | |
(0.4693768015868821, (2, 5, 0)), | |
(2.3468840079344107, (4, 3, 0)), | |
(-12.516714708983523, (0, 3, 4)), | |
(37.55014412695057, (2, 1, 4)), | |
(1.4081304047606462, (6, 1, 0)), | |
(9.387536031737643, (0, 5, 2)), | |
(-28.162608095212928, (4, 1, 2))], | |
[(13.27598077334948, (3, 3, 1)), | |
(6.63799038667474, (1, 5, 1)), | |
(-35.402615395598616, (3, 1, 3)), | |
(21.24156923735917, (1, 1, 5)), | |
(-35.402615395598616, (1, 3, 3)), | |
(6.63799038667474, (5, 1, 1))], | |
[(-0.4516580379125865, (0, 7, 0)), | |
(10.839792909902076, (0, 5, 2)), | |
(-1.3549741137377596, (2, 5, 0)), | |
(-1.3549741137377596, (4, 3, 0)), | |
(-21.679585819804153, (0, 3, 4)), | |
(-21.679585819804153, (2, 1, 4)), | |
(5.781222885281108, (0, 1, 6)), | |
(-0.4516580379125865, (6, 1, 0)), | |
(21.679585819804153, (2, 3, 2)), | |
(10.839792909902076, (4, 1, 2))], | |
[(-11.471758521216831, (2, 0, 5)), | |
(1.0925484305920792, (0, 0, 7)), | |
(-11.471758521216831, (0, 2, 5)), | |
(28.67939630304208, (2, 2, 3)), | |
(-2.3899496919201733, (6, 0, 1)), | |
(-7.16984907576052, (4, 2, 1)), | |
(14.33969815152104, (4, 0, 3)), | |
(-2.3899496919201733, (0, 6, 1)), | |
(-7.16984907576052, (2, 4, 1)), | |
(14.33969815152104, (0, 4, 3))], | |
[(10.839792909902076, (1, 4, 2)), | |
(-0.4516580379125865, (7, 0, 0)), | |
(21.679585819804153, (3, 2, 2)), | |
(-1.3549741137377596, (5, 2, 0)), | |
(-0.4516580379125865, (1, 6, 0)), | |
(-21.679585819804153, (3, 0, 4)), | |
(-1.3549741137377596, (3, 4, 0)), | |
(5.781222885281108, (1, 0, 6)), | |
(-21.679585819804153, (1, 2, 4)), | |
(10.839792909902076, (5, 0, 2))], | |
[(10.620784618679584, (2, 0, 5)), | |
(-10.620784618679584, (0, 2, 5)), | |
(3.31899519333737, (6, 0, 1)), | |
(3.31899519333737, (4, 2, 1)), | |
(-17.701307697799308, (4, 0, 3)), | |
(-3.31899519333737, (0, 6, 1)), | |
(-3.31899519333737, (2, 4, 1)), | |
(17.701307697799308, (0, 4, 3))], | |
[(-1.4081304047606462, (1, 6, 0)), | |
(0.4693768015868821, (7, 0, 0)), | |
(18.775072063475285, (3, 2, 2)), | |
(-0.4693768015868821, (5, 2, 0)), | |
(12.516714708983523, (3, 0, 4)), | |
(-2.3468840079344107, (3, 4, 0)), | |
(28.162608095212928, (1, 4, 2)), | |
(-37.55014412695057, (1, 2, 4)), | |
(-9.387536031737643, (5, 0, 2))], | |
[(10.378311574405206, (4, 0, 3)), | |
(-3.1134934723215615, (0, 6, 1)), | |
(15.56746736160781, (2, 4, 1)), | |
(-62.26986944643124, (2, 2, 3)), | |
(10.378311574405206, (0, 4, 3)), | |
(-3.1134934723215615, (6, 0, 1)), | |
(15.56746736160781, (4, 2, 1))], | |
[(-2.5945778936013015, (1, 6, 0)), | |
(-62.26986944643124, (3, 2, 2)), | |
(-0.5189155787202603, (7, 0, 0)), | |
(31.13493472321562, (1, 4, 2)), | |
(2.5945778936013015, (3, 4, 0)), | |
(6.226986944643123, (5, 0, 2)), | |
(4.670240208482342, (5, 2, 0))], | |
[(2.6459606618019005, (6, 0, 1)), | |
(-2.6459606618019005, (0, 6, 1)), | |
(-39.68940992702851, (4, 2, 1)), | |
(39.68940992702851, (2, 4, 1))], | |
[(0.7071627325245963, (7, 0, 0)), | |
(-14.850417383016522, (5, 2, 0)), | |
(24.75069563836087, (3, 4, 0)), | |
(-4.950139127672174, (1, 6, 0))]] | |
self.YL = YL | |
return | |
class GPaw: | |
def __init__(self, fname: str='N.PBE.gz'): | |
self.parse_psfile(fname) | |
self.calculate_compensation_charges() | |
self.calculate_integral_potentials() | |
self.calculate_Delta_lq() | |
_np = self.ni * (self.ni + 1) // 2 | |
self.calculate_T_Lqp(self.lcut, _np, self.nj, self.jlL_i) | |
self.calculate_coulomb_corrections( | |
self.wn_lqg, self.wnt_lqg, self.wg_lg, self.wnc_g, self.wmct_g) | |
return | |
def parse_psfile(self, fname:str): | |
txt = gzip.open(fname, 'rb').read() | |
tree = ET.fromstring(txt) | |
self.build_atom_spec(tree.find('atom').attrib) | |
self.build_radial_grid(tree.find('radial_grid').attrib) | |
self.build_l(tree) | |
self.build_shape_function(tree.find('shape_function').attrib, self.lmax) | |
self.build_paw_functions(tree) | |
return | |
def build_l(self, tree): | |
self.l_j = [int(x.attrib['l']) for x in tree.find('valence_states')] | |
self.lmax = 2 | |
self.lcut = max(self.l_j) | |
rcut_j = [float(x.attrib['rc']) for x in tree.find('valence_states')] | |
rcut2 = max(rcut_j) * 2 | |
self.rcut_j = rcut_j | |
self.rcut2 = rcut2 | |
self.gcut2 = np.searchsorted(self.r_g, rcut2) | |
self.n_j = [int(x.attrib.get('n', -1)) for x in tree.find('valence_states')] | |
self.f_j = [float(x.attrib.get('f', 0)) for x in tree.find('valence_states')] | |
self.eps_j = [float(x.attrib['e']) for x in tree.find('valence_states')] | |
self.rcut_j = [float(x.attrib.get('rc', -1)) for x in tree.find('valence_states')] | |
self.id_j = [x.attrib['id'] for x in tree.find('valence_states')] | |
jlL_i = [(j, l, l**2+m) | |
for (j, l) in enumerate(self.l_j) | |
for m in range(2*l + 1)] | |
self.jlL_i = jlL_i | |
self.ni = len(jlL_i) | |
self.nj = len(self.l_j) | |
self.nq = self.nj * (self.nj + 1) // 2 | |
return | |
def build_atom_spec(self, dic: dict): | |
self.symbol = dic['symbol'] | |
self.Z = int(float(dic['Z'])) | |
self.core = int(float(dic['core'])) | |
self.valence = int(float(dic['valence'])) | |
return | |
def build_radial_grid(self, dic: dict): | |
eq = dic['eq'] | |
if 'r=a*i/(n-i)' == eq: | |
n = int(dic['n']) | |
a = float(dic['a']) / n | |
b = 1.0 / n | |
elif 'r=a*i/(1-b*i)' == eq: | |
a = float(dic['a']) | |
b = float(dic['b']) | |
n = int(dic['n']) | |
else: | |
raise ValueError(f"Invalid radial grid eq: {eq}") | |
g = np.arange(n) | |
r_g = a * g / (1 - b * g) | |
dr_g = (b * r_g + a)**2 / a | |
self.r_g = r_g | |
self.dr_g = dr_g | |
self.rdr_g = r_g * dr_g | |
return | |
def build_shape_function(self, dic: dict, lmax: int): | |
r_g = self.r_g | |
ng = r_g.size | |
g_lg = np.zeros((lmax+1, ng)) | |
typ = dic['type'] | |
rc = float(dic['rc']) | |
if 'gauss' == typ: | |
g_lg[0,:] = 4 / rc**3 / np.sqrt(np.pi) * np.exp(-(r_g / rc)**2) | |
for l in range(1, lmax+1): | |
g_lg[l,:] = 2.0 / (2*l + 1) / rc**2 * r_g * g_lg[l-1,:] | |
else: | |
raise ValueError(f"Invalid type of shape function: {typ}") | |
for l in range(lmax+1): | |
g_lg[l] /= self.rgd_integrate(g_lg[l], l) / (4 * np.pi) | |
self.g_lg = g_lg | |
return | |
def build_paw_functions(self, tree): | |
self.nc_g = np.array( | |
tree.find('ae_core_density').text.split(), | |
dtype=float) | |
self.nct_g = np.array( | |
tree.find('pseudo_core_density').text.split(), | |
dtype=float) | |
self.phi_g = np.array( | |
[ae.text.split() for ae in tree.findall('ae_partial_wave')], | |
dtype=float) | |
self.phit_g = np.array( | |
[ae.text.split() for ae in tree.findall('pseudo_partial_wave')], | |
dtype=float) | |
return | |
def rgd_integrate(self, a_xg: npt.NDArray, n: int=0): | |
assert n >= -2 | |
return np.dot(a_xg[..., 1:], | |
(self.r_g**(2+n) * self.dr_g)[1:]) * (4 * np.pi) | |
# 69us, corrected now | |
@staticmethod | |
def hartree(l: int, nrdr: npt.NDArray, r: npt.NDArray): | |
M = nrdr.size | |
vr = np.zeros(M, dtype=float) | |
rl = r[1:]**l | |
rlp1 = rl * r[1:] | |
dp = nrdr[1:] / rl | |
dq = nrdr[1:] * rlp1 | |
dpfl = np.flip(dp) | |
dqfl = np.flip(dq) | |
p = np.flip(np.r_[0, np.cumsum(dpfl)]) # prepend 0 to cumsum | |
q = np.flip(np.r_[0, np.cumsum(dqfl)]) | |
vr[1:] = (p[1:] + 0.5 * dp) * rlp1 - (q[1:] + 0.5 * dq) / rl | |
vr[0] = 0.0 | |
f = 4.0 * np.pi / (2 * l + 1) | |
vr[1:] = f * (vr[1:] + q[0] / rl) | |
return vr | |
## 424us, reference implementation from gpaw/c/utilities.c | |
# @staticmethod | |
# def hartree2(l, nrdr, r): | |
# M = nrdr.size | |
# | |
# vr = np.zeros(M) | |
# | |
# p = 0.0 | |
# q = 0.0 | |
# | |
# for g in range(M-1, 0, -1): | |
# R = r[g] | |
# rl = R**l | |
# rlp1 = rl * R | |
# dp = nrdr[g] / rl | |
# dq = nrdr[g] * rlp1 | |
# vr[g] = (p + 0.5 * dp) * rlp1 - (q + 0.5 * dq) / rl | |
# p += dp | |
# q += dq | |
# | |
# vr[0] = 0.0 | |
# f = 4.0 * np.pi / (2 * l + 1) | |
# | |
# for g in range(1, M): | |
# R = r[g] | |
# vr[g] = f * (vr[g] + q / R**l) | |
# return vr | |
def calculate_compensation_charges(self): | |
# lmax = self.lmax | |
gcut2 = self.gcut2 | |
# g_lg = self.g_lg | |
nq = self.nq | |
phi_g = self.phi_g[:,:gcut2] | |
phit_g = self.phit_g[:,:gcut2] | |
n_qg = np.zeros((nq, gcut2)) | |
nt_qg = np.zeros((nq, gcut2)) | |
for (q, (j1, j2)) in enumerate([(j1, j2) for j1 in range(self.nj) | |
for j2 in range(j1,self.nj)]): | |
n_qg[q,:] = phi_g[j1,:] * phi_g[j2,:] # phi_i1^a * phi_i2^a | |
nt_qg[q,:] = phit_g[j1,:] * phit_g[j2,:] # ~phi_i1^a * ~phi_i2^a | |
self.n_qg = n_qg | |
self.nt_qg = nt_qg | |
## Delta0 is an constant for each atom | |
self.Delta0 = np.dot(self.nc_g[:gcut2] - self.nct_g[:gcut2], # | |
self.rdr_g[:gcut2] * self.r_g[:gcut2]) - self.Z / np.sqrt(4 * np.pi) | |
return | |
def poisson(self, n_g, l=0, *, s:slice=slice(None)): | |
n_g = n_g[s].copy() | |
nrdr_g = n_g[s] * self.rdr_g[s] | |
return GPaw.hartree(l, nrdr_g, self.r_g[s]) | |
def calculate_integral_potentials(self): | |
def H(n_g, l, *, s:slice=slice(None)): | |
return self.poisson(n_g[s], l, s=s) * self.r_g[s] * self.dr_g[s] | |
gcut2 = self.gcut2 | |
wg_lg = [H(self.g_lg[l,:], l, s=slice(None,gcut2)) | |
for l in range(self.lmax + 1)] # ((~g_l^a)) in Eq (47) | |
wn_lqg = [np.array([H(self.n_qg[q,:], l, s=slice(None,gcut2)) | |
for q in range(self.nq)]) | |
for l in range(2*self.lcut + 1)] # ( phi_i1^a * phi_i2^a | phi_i3^a * phi_i4^a * r^l) in Eq (47) | |
wnt_lqg = [np.array([H(self.nt_qg[q,:], l, s=slice(None,gcut2)) | |
for q in range(self.nq)]) | |
for l in range(2*self.lcut + 1)] # (~phi_i1^a * ~phi_i2^a | ~phi_i3^a * ~phi_i4^a * r^l) in Eq (47) | |
wnc_g = H(self.nc_g[:], l=0, s=slice(None,gcut2)) # (( n_c^a)) | |
wnct_g = H(self.nct_g[:], l=0, s=slice(None,gcut2)) # ((~n_c^a)) | |
wmct_g = wnct_g + self.Delta0 * wg_lg[0] | |
self.wg_lg = wg_lg | |
self.wn_lqg = wn_lqg | |
self.wnt_lqg = wnt_lqg | |
self.wnc_g = wnc_g | |
self.wnct_g = wnct_g | |
self.wmct_g = wmct_g | |
return | |
def calculate_T_Lqp(self, lcut, _np, nj, jlL_i): | |
''' | |
T_Lqp is the Gaunt-Coefficients. | |
T_Lqp[L, l1 l2, p1 p2] = G_LLL[L1, L2, L] | |
''' | |
Lcut = (2*lcut + 1)**2 | |
gaunt = Gaunt() | |
G_LLL = gaunt(max(self.l_j))[:, :, :Lcut] | |
LGcut = G_LLL.shape[2] | |
T_Lqp = np.zeros((Lcut, self.nq, _np)) | |
p = 0 | |
i1 = 0 | |
for j1, l1, L1 in jlL_i: | |
for j2, l2, L2 in jlL_i[i1:]: | |
if j1 < j2: | |
q = j2 + j1 * nj - j1 * (j1 + 1) // 2 | |
else: | |
q = j1 + j2 * nj - j2 * (j2 + 1) // 2 | |
T_Lqp[:LGcut, q, p] = G_LLL[L1, L2, :] | |
p += 1 | |
i1 += 1 | |
self.T_Lqp = T_Lqp | |
return | |
def calculate_Delta_lq(self): | |
gcut2 = self.gcut2 | |
r_g = self.r_g[:gcut2] | |
dr_g = self.dr_g[:gcut2] | |
n_qg = self.n_qg | |
nt_qg = self.nt_qg | |
Delta_lq = np.zeros((self.lmax + 1, self.nq)) | |
for l in range(self.lmax + 1): | |
Delta_lq[l,:] = (n_qg - nt_qg) @ (r_g**(l+2) * dr_g) # \sum dr * r^l * ( phi_i1 * phi_i2 - ~phi_i1 * ~phi_i2) | |
self.Delta_lq = Delta_lq # Delta_Li1i2^a in Eq (41b) (without Y_L(r) part) | |
return | |
def calculate_coulomb_corrections(self, wn_lqg, wnt_lqg, wg_lg, wnc_g, wmct_g): | |
gcut2 = self.gcut2 | |
_np = self.ni * (self.ni + 1) // 2 | |
mct_g = self.nct_g[:gcut2] + self.Delta0 * self.g_lg[0, :gcut2] # ~n_c^a + Delta^a * ~g_00^a | |
rdr_g = self.r_g[:gcut2] * self.dr_g[:gcut2] | |
A_q = 0.5 * (wn_lqg[0] @ self.nc_g[:gcut2] + self.n_qg @ wnc_g) # (phi_i1 * phi_i2 | n_c^a) + | |
A_q -= np.sqrt(4 * np.pi) * self.Z * (self.n_qg @ rdr_g) | |
A_q -= 0.5 * (wn_lqg[0] @ mct_g + self.nt_qg @ wmct_g) | |
A_q -= 0.5 * (mct_g @ wg_lg[0] + self.g_lg[0,:gcut2] @ wmct_g) * self.Delta_lq[0,:] | |
M_p = A_q @ self.T_Lqp[0] # DeltaC_i1i2^a in Eq (46) | |
A_lqq = [] | |
for l in range(2 * self.lcut + 1): | |
A_qq = 0.5 * self.n_qg @ wn_lqg[l].T | |
A_qq -= 0.5 * self.nt_qg @ wnt_lqg[l].T # 1/2 * [ ( | ) - ( ~ | ~ ) ] in Eq (47) | |
if l <= self.lmax: | |
A_qq -= 0.5 * np.outer(self.Delta_lq[l,:], # 1/2 * Delta_Li1i2^a (~phi_i1^a * ~phi_i2^a | ~g_l^a) | |
wnt_lqg[l] @ self.g_lg[l,:gcut2]) | |
A_qq -= 0.5 * np.outer(self.nt_qg @ wg_lg[l], # 1/2 * Delta_Li3i4^a (~phi_i3^a * ~phi_i4^a | ~g_l^a) | |
self.Delta_lq[l,:]) | |
A_qq -= 0.5 * ((self.g_lg[l,:gcut2] @ wg_lg[l]) # Delta_Li1i2^a * ((~g_l^a)) * Delta_Li3i4 | |
* np.outer(self.Delta_lq[l], self.Delta_lq[l])) | |
A_lqq.append(A_qq) | |
pass | |
M_pp = np.zeros((_np, _np)) # DeltaC_i1i2i3i4^a in Eq (47) | |
L = 0 | |
for l in range(2 * self.lcut + 1): | |
for m in range(2 * l + 1): | |
M_pp += self.T_Lqp[L].T @ A_lqq[l] @ self.T_Lqp[L] # Multiple all the quantities with the angular term | |
L += 1 | |
self.M_p = M_p | |
self.M_pp = M_pp | |
return | |
def get_coulomb_corrections(self): | |
# if not hasattr(self, 'M_pp') or not hasattr(self, 'M_p'): | |
# self.calculate_coulomb_corrections( | |
# self.wn_lqg, self.wnt_lqg, self.wg_lg, self.wnc_g, self.wmct_g | |
# ) | |
return self.M_p, self.M_pp | |
def pack(A) -> npt.NDArray: | |
ni = A.shape[0] | |
N = ni * (ni + 1) // 2 | |
B = np.zeros(N, dtype=A.dtype) | |
k = 0 | |
for i in range(ni): | |
B[k] = A[i,i] | |
k += 1 | |
for j in range(i+1, ni): | |
B[k] = A[i,j] + A[j,i] | |
k += 1 | |
return B | |
if '__main__' == __name__: | |
gaunt = Gaunt() | |
xx = GPaw("./N.PBE.gz") | |
M_p, M_pp = xx.get_coulomb_corrections() | |
# for fname in glob('/public/home/chenlj/.gpaw/gpaw-setups-0.9.20000/*.gz'): | |
# if 'basis.gz' in fname: | |
# continue | |
# print(fname) | |
# xx = GPaw(fname) | |
# M_p, M_pp = xx.get_coulomb_corrections() | |
# print(M_pp) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment