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