Skip to content

Commit e2426bc

Browse files
committed
feat(dftb): add atomic dft calculation module for sk tables generation
Implement DFT2SKTable class to compute Slater-Koster tables using hotcent API - Supports atomic configuration input and confinement parameters - Handles basis set validation and electronic configuration - Computes onsite energies, occupations and Hubbard U values - Generates SK tables for homo and hetero atomic pairs
1 parent 63f2b02 commit e2426bc

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

dptb/nn/dftb/atomicdft.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# this file is for atomic dft calculation
2+
# given atomic configuration, return sk tables.
3+
# using hotcent api.
4+
5+
from ase.units import Bohr, Ha
6+
from hotcent.atomic_dft import AtomicDFT
7+
from hotcent.confinement import PowerConfinement
8+
from hotcent.offsite_twocenter import Offsite2cTable
9+
from dptb.utils.tools import atomic_num_dict
10+
from dptb.nn.sktb.cov_radiiDB import Covalent_radii
11+
from typing import Union,Dict, List
12+
from dptb.nn.sktb.electronic_configDB import electronic_config_dict
13+
from dptb.nn.sktb.builtin_skbasisDB import skbasisDB
14+
from dptb.nn.sktb.builtin_skbasisDB import onsite_e_builtin_basis, occupations_builtin_basis, Hubbard_U_builtin_basis
15+
import logging
16+
log = logging.getLogger(__name__)
17+
18+
19+
class DFT2SKTable(object):
20+
def __init__(self, xc: str, superposition: str = 'density', scalarrel=True, **kwargs):
21+
self.xc = xc
22+
self.superposition = superposition
23+
self.scalarrel = scalarrel
24+
self.kwargs = kwargs
25+
self.atomic_objs = {}
26+
27+
def update_config(self, basis:Dict[List], rw: dict, pw:dict, rd:dict=None, pd:dict=None):
28+
atomic_symbols = list(basis.keys())
29+
# check basis
30+
for ia in atomic_symbols:
31+
assert isinstance(basis[ia], list)
32+
for ib in basis[ia]:
33+
assert ib in electronic_config_dict[ia]['valence'].keys(), f'the {ia}-{ib} not in electronic_config_dict, check dptb.nn.sktb.electronic_configDB'
34+
35+
if rd is None:
36+
rd = rw
37+
if pd is None:
38+
pd = pw
39+
for ia in atomic_symbols:
40+
if ia in self.atomic_objs:
41+
# run_completed 判断是否运行atomdft.run()
42+
assert 'run_completed' in self.atomic_objs[ia]
43+
if rd[ia] == self.atomic_objs[ia]['rd'] and pd[ia] == self.atomic_objs[ia]['pd'] and \
44+
rw[ia] == self.atomic_objs[ia]['rw'] and pw[ia] == self.atomic_objs[ia]['pw']:
45+
continue
46+
else:
47+
self.atomic_objs[ia] = {}
48+
49+
atomic_config = electronic_config_dict[ia]
50+
electronic_config = atomic_config['atomic_core'] + " " + " ".join(list(atomic_config['valence'].keys()))
51+
valences = skbasisDB[ia]
52+
53+
confinement_density = PowerConfinement(r0=rd[ia], s=pd[ia])
54+
confinement_wavefunc = {}
55+
for val in valences: # set confinement for each valence
56+
confinement_wavefunc[val] = PowerConfinement(r0=(rw[ia]), s=pw[ia])
57+
58+
atomdft = AtomicDFT(ia,
59+
xc=self.xc,
60+
configuration=electronic_config,
61+
valence=valences,
62+
scalarrel=True,
63+
confinement=confinement_density,
64+
wf_confinement=confinement_wavefunc,
65+
txt='-',
66+
)
67+
68+
# constuct atomic_objs
69+
onsite_e = onsite_e_builtin_basis(ia, basis[ia],unit='Ha')
70+
occupations = occupations_builtin_basis(ia, basis[ia])
71+
hubbardvalues = Hubbard_U_builtin_basis(ia, basis[ia],unit='Ha')
72+
73+
self.atomic_objs[ia].update({'basis': basis[ia],
74+
'rd': rd[ia],
75+
'pd': pd[ia],
76+
'rw': rw[ia],
77+
'pw': pw[ia],
78+
'atomdft': atomdft,
79+
'run_completed': False,
80+
'eigenvalues': onsite_e[ia],
81+
'occupations': occupations[ia],
82+
'hubbardvalues':hubbardvalues[ia]}
83+
)
84+
# U values need
85+
def run_atomic_dft(self):
86+
for ia in self.atomic_objs:
87+
if self.atomic_objs[ia]['run_completed']:
88+
continue
89+
self.atomic_objs[ia]['atomdft'].run()
90+
self.atomic_objs[ia]['run_completed'] = True
91+
#self.atomic_objs[ia]['atomdft'].info = {'hubbardvalues': {}}
92+
#self.atomic_objs[ia]['atomdft'].info['hubbardvalues'] = self.atomic_objs[ia]['hubbardvalues']
93+
#self.atomic_objs[ia]['atomdft'].info['occupations'] = self.atomic_objs[ia]['occupations']
94+
#self.atomic_objs[ia]['atomdft'].info['eigenvalues'] = self.atomic_objs[ia]['eigenvalues']
95+
96+
def get_skf_pair(self, atom_a:str, atom_b:str=None, rmin=0.4, dr=0.02, N = 800, stride=1):
97+
if atom_b is None:
98+
atom_b = atom_a
99+
log.info(f'getting {atom_a}-{atom_b} sk table')
100+
assert atom_a in self.atomic_objs and atom_b in self.atomic_objs
101+
102+
for ia in [atom_a, atom_b]:
103+
if not self.atomic_objs[ia]['run_completed']:
104+
self.atomic_objs[ia]['atomdft'].run()
105+
self.atomic_objs[ia]['run_completed'] = True
106+
log.info(f'finished runing the atomicdfts ....')
107+
108+
off2c = Offsite2cTable(self.atomic_objs[atom_a]['atomdft'], self.atomic_objs[atom_b]['atomdft'])
109+
off2c.run(rmin, dr, N, superposition=self.superposition,
110+
xc=self.xc,stride=stride, smoothen_tails=True)
111+
log.info(f'finished runing sk tables calculations on r-grids....')
112+
# Write the SK tables without repulsion (only electronic part)
113+
# for homo-case, the atomic eigenvalues, Hubbardvalues, occupations are also saved
114+
# but the spe as well as the (spin-polarization error) is set to 0.0.
115+
116+
if atom_a == atom_b:
117+
sk.write(eigenvalues=self.atomic_objs[atom_a]['eigenvalues'],
118+
hubbardvalues=self.atomic_objs[atom_a]['hubbardvalues'],
119+
occupations=self.atomic_objs[atom_a]['occupations'],
120+
spe=0.
121+
)
122+
else:
123+
sk.write()
124+
log.info(f'finished writing sk tables....')
125+
126+
def get_skfs(self, basis:Dict[List], rw: dict, pw:dict, rd:dict=None, pd:dict=None):
127+
self.update_config(basis, rd, pw, rw, pd)
128+
self.run_atomic_dft()
129+
atom_symbols = list(self.atomic_objs.keys())
130+
for ia in range(len(atom_symbols)):
131+
atoms_a = atom_symbols[ia]
132+
for atoms_b in atom_symbols[ia:]:
133+
self.get_skf_pair(atoms_a, atoms_b)
134+
135+

0 commit comments

Comments
 (0)