FT-inversion-tools 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
FTI_analysis_tools.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import numpy as np
|
|
3
|
+
import scipy as sp
|
|
4
|
+
### Functions for ZT system
|
|
5
|
+
def getZTFilePaths(system=str, direction=str):
|
|
6
|
+
"""
|
|
7
|
+
Reads data for the FT system
|
|
8
|
+
"""
|
|
9
|
+
default_path = os.path.join('~','ft_inversion_paper', 'ZT_data', system)
|
|
10
|
+
dens_path = os.path.expanduser(os.path.join(default_path, direction, 'static', 'density.y=0,z=0'))
|
|
11
|
+
vks_path = os.path.expanduser(os.path.join(default_path, direction, 'static', 'vks.y=0,z=0'))
|
|
12
|
+
vxc_path = os.path.expanduser(os.path.join(default_path, direction, 'static', 'vxc.y=0,z=0'))
|
|
13
|
+
vh_path = os.path.expanduser(os.path.join(default_path, direction, 'static', 'vh.y=0,z=0'))
|
|
14
|
+
return dens_path, vks_path, vxc_path, vh_path
|
|
15
|
+
|
|
16
|
+
def getZTData(system=str, direction=str):
|
|
17
|
+
"""
|
|
18
|
+
Reads data for the FT system
|
|
19
|
+
"""
|
|
20
|
+
dens_path, vks_path, vxc_path, vh_path = getZTFilePaths(system, direction)
|
|
21
|
+
x_grid = np.loadtxt(dens_path)[:,0] # 1D grid
|
|
22
|
+
dens = np.loadtxt(dens_path)[:,1]
|
|
23
|
+
vks = np.loadtxt(vks_path)[:,1]
|
|
24
|
+
vxc = np.loadtxt(vxc_path)[:,1]
|
|
25
|
+
vh = np.loadtxt(vh_path)[:,1]
|
|
26
|
+
return x_grid, dens, vks, vxc, vh
|
|
27
|
+
|
|
28
|
+
### Functions for FT system
|
|
29
|
+
def getFTFilePaths(system=str, temp=str, direction=str):
|
|
30
|
+
"""
|
|
31
|
+
Reads data for the FT system
|
|
32
|
+
"""
|
|
33
|
+
default_path = os.path.join('~','ft_inversion_paper', 'ft_inversions', system)
|
|
34
|
+
dens_path = os.path.expanduser(os.path.join(default_path, temp, direction, 'static', 'density.y=0,z=0'))
|
|
35
|
+
vks_path = os.path.expanduser(os.path.join(default_path, temp, direction, 'static', 'vks.y=0,z=0'))
|
|
36
|
+
vxc_path = os.path.expanduser(os.path.join(default_path, temp, direction, 'static', 'vxc.y=0,z=0'))
|
|
37
|
+
vh_path = os.path.expanduser(os.path.join(default_path, temp, direction, 'static', 'vh.y=0,z=0'))
|
|
38
|
+
return dens_path, vks_path, vxc_path, vh_path
|
|
39
|
+
|
|
40
|
+
def getFTData(temp=str, system=str, direction=str):
|
|
41
|
+
"""
|
|
42
|
+
Reads data for the FT system
|
|
43
|
+
"""
|
|
44
|
+
dens_path, vks_path, vxc_path, vh_path = getFTFilePaths(temp, system, direction)
|
|
45
|
+
x_grid = np.loadtxt(dens_path)[:,0] # 1D grid
|
|
46
|
+
dens = np.loadtxt(dens_path)[:,1]
|
|
47
|
+
vks = np.loadtxt(vks_path)[:,1]
|
|
48
|
+
vxc = np.loadtxt(vxc_path)[:,1]
|
|
49
|
+
vh = np.loadtxt(vh_path)[:,1]
|
|
50
|
+
return x_grid, dens, vks, vxc, vh
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def shifter(temps, vks_list_FWD, vks_list_INV, vxc_list_INV, Fermi_energy_list):
|
|
54
|
+
shifted_ks = []
|
|
55
|
+
shifted_xc = []
|
|
56
|
+
shifted_fermi = []
|
|
57
|
+
for i in range(len(temps)):
|
|
58
|
+
# print(temps[i])
|
|
59
|
+
timpFWDKS = vks_list_FWD[i]
|
|
60
|
+
timpINVKS = vks_list_INV[i]
|
|
61
|
+
shift = np.mean(timpINVKS- timpFWDKS)
|
|
62
|
+
shifted_ks.append(vks_list_INV[i] + shift)
|
|
63
|
+
shifted_xc.append(vxc_list_INV[i] + shift)
|
|
64
|
+
shifted_fermi.append(Fermi_energy_list[i] + shift)
|
|
65
|
+
return shifted_ks, shifted_xc, shifted_fermi
|
|
66
|
+
|
|
67
|
+
def energy_calculator(temps, vxc_list, dens_list, grid_list):
|
|
68
|
+
Exc_list = []
|
|
69
|
+
for i in range(len(temps)):
|
|
70
|
+
Exc = -sp.integrate.simpson((np.diff(vxc_list[0])) * (dens_list[i][1:]*grid_list[i][1:]), grid_list[i][1:])
|
|
71
|
+
Exc_list.append(Exc)
|
|
72
|
+
return Exc_list
|
|
73
|
+
|
|
74
|
+
def diffs_calculator(temps, vxc_list, dens_list):
|
|
75
|
+
potential_diffs = []
|
|
76
|
+
density_diffs = []
|
|
77
|
+
for i in range(len(temps)):
|
|
78
|
+
xc_diff = vxc_list[i] - vxc_list[0]
|
|
79
|
+
potential_diffs.append(xc_diff)
|
|
80
|
+
dens_diff = dens_list[i] - dens_list[0]
|
|
81
|
+
density_diffs.append(dens_diff)
|
|
82
|
+
return potential_diffs, density_diffs
|
|
83
|
+
|
ZTA_analysis_tools.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import numpy as np
|
|
3
|
+
import scipy as sp
|
|
4
|
+
import pickle
|
|
5
|
+
## Root finding functions
|
|
6
|
+
def secant_method(function, guess1:float, print_opt:bool, criterion:float=1e-6, error_track:bool=False):
|
|
7
|
+
"""
|
|
8
|
+
INPUT:
|
|
9
|
+
function : function, function of which to find the roots
|
|
10
|
+
guess1 : float, lower guess for the root
|
|
11
|
+
criterion : float, convergence criterion for the root finding method
|
|
12
|
+
max_iter : float, maximum number of iterations for the root finding method
|
|
13
|
+
Returns:
|
|
14
|
+
root : float, The root of the function
|
|
15
|
+
Raises:
|
|
16
|
+
Excpetion: Divide by zero warning if guess1 and guess2 are equal
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
x2 = guess1
|
|
20
|
+
x1 = guess1 - 5
|
|
21
|
+
|
|
22
|
+
error = 1
|
|
23
|
+
iteration = 0
|
|
24
|
+
|
|
25
|
+
error = -(function(x2)*(x2 - x1))/(function(x2)-function(x1))
|
|
26
|
+
|
|
27
|
+
if print_opt ==True:
|
|
28
|
+
with open("secant_error.txt", "a") as f:
|
|
29
|
+
print("Iteration, x1, x2, f(x1), f(x2), error", file=f)
|
|
30
|
+
|
|
31
|
+
while (abs(error) > criterion and iteration < 1000):
|
|
32
|
+
if print_opt == True:
|
|
33
|
+
with open("secant_error.txt", "a") as f:
|
|
34
|
+
print(iteration, x1, x2, function(x1), function(x2), error, file=f)
|
|
35
|
+
x1 = x2
|
|
36
|
+
x2 += error
|
|
37
|
+
iteration += 1
|
|
38
|
+
error = -function(x2)*(x2 - x1)/(function(x2)-function(x1))
|
|
39
|
+
if print_opt == True:
|
|
40
|
+
with open("secant_error.txt", "a") as f:
|
|
41
|
+
print(iteration, x1, x2, function(x1), function(x2), error, file=f)
|
|
42
|
+
|
|
43
|
+
if error_track == False:
|
|
44
|
+
return x2, function(x2), iteration, error
|
|
45
|
+
return x2, function(x2)
|
|
46
|
+
|
|
47
|
+
## Boltzman functions 2+ electron systems
|
|
48
|
+
|
|
49
|
+
def boltzman_weights(energy, chem_pot, tau, part_num):
|
|
50
|
+
"""Calculates the Boltzman weights for the interacting densities
|
|
51
|
+
to approximate a thermal interacting density
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
energy (ndarray): _description_
|
|
55
|
+
chem_pot (float): _description_
|
|
56
|
+
tau (float): _description_
|
|
57
|
+
part_num (float): _description_
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
occupation: boltzman weight for given temperature
|
|
61
|
+
"""
|
|
62
|
+
kb = 1 # Boltzman constant in atomic units
|
|
63
|
+
beta = 1/(kb*tau) # beta
|
|
64
|
+
partition_function = 0
|
|
65
|
+
nstates = len(energy)
|
|
66
|
+
w = np.empty((nstates))
|
|
67
|
+
for i in range(part_num):
|
|
68
|
+
for j in range(nstates):
|
|
69
|
+
w[j] = np.exp(-beta*(energy[j]-(chem_pot*(i))))
|
|
70
|
+
partition_function += w[j]
|
|
71
|
+
w = w/partition_function
|
|
72
|
+
occupation = w
|
|
73
|
+
return occupation
|
|
74
|
+
|
|
75
|
+
def boltz_num_func_func(x, tau, vals, densities, ne, target_ne):
|
|
76
|
+
'''
|
|
77
|
+
Description: Determine the Unshifted particle number
|
|
78
|
+
INPUT:
|
|
79
|
+
mu: Scalar (float)
|
|
80
|
+
chemical potential
|
|
81
|
+
tau: Scalar (float)
|
|
82
|
+
Electronic temperature
|
|
83
|
+
vecs: ndarray
|
|
84
|
+
Eigenvectors
|
|
85
|
+
vals: ndarray
|
|
86
|
+
Eigenvalues
|
|
87
|
+
x: ndarray
|
|
88
|
+
Grid
|
|
89
|
+
OUTPUT
|
|
90
|
+
Ne: Scalar (float)
|
|
91
|
+
The unshifted particle number
|
|
92
|
+
'''
|
|
93
|
+
|
|
94
|
+
def boltz_num_func(mu):
|
|
95
|
+
|
|
96
|
+
nx = len(x)
|
|
97
|
+
nk = vals.shape[0]
|
|
98
|
+
|
|
99
|
+
kb = 1 #3.166811563e-6 # Ha K^-1
|
|
100
|
+
T = tau/kb
|
|
101
|
+
|
|
102
|
+
# obtain boltzman weights
|
|
103
|
+
w = boltzman_weights(vals,mu,T,ne)
|
|
104
|
+
dens = np.zeros(nx)
|
|
105
|
+
for i in range(ne):
|
|
106
|
+
for j in range(nk):
|
|
107
|
+
dens += w[j]*densities[j,:]
|
|
108
|
+
Ne = np.trapezoid(dens,x)
|
|
109
|
+
|
|
110
|
+
return Ne - target_ne
|
|
111
|
+
|
|
112
|
+
return boltz_num_func
|
|
113
|
+
## Fermi Functions for 1 electron systems
|
|
114
|
+
def fermi_weights(energy, chem_pot, tau):
|
|
115
|
+
F_occs = 1/(1+np.exp((energy-chem_pot)/tau))
|
|
116
|
+
return F_occs
|
|
117
|
+
def fermi_num_func_func(x, tau, vals, densities, ne, target_ne):
|
|
118
|
+
'''
|
|
119
|
+
Description: Determine the Unshifted particle number
|
|
120
|
+
INPUT:
|
|
121
|
+
mu: Scalar (float)
|
|
122
|
+
chemical potential
|
|
123
|
+
tau: Scalar (float)
|
|
124
|
+
Electronic temperature
|
|
125
|
+
vecs: ndarray
|
|
126
|
+
Eigenvectors
|
|
127
|
+
vals: ndarray
|
|
128
|
+
Eigenvalues
|
|
129
|
+
x: ndarray
|
|
130
|
+
Grid
|
|
131
|
+
OUTPUT
|
|
132
|
+
Ne: Scalar (float)
|
|
133
|
+
The unshifted particle number
|
|
134
|
+
'''
|
|
135
|
+
|
|
136
|
+
def fermi_num_func(mu):
|
|
137
|
+
|
|
138
|
+
nx = len(x)
|
|
139
|
+
nk = vals.shape[0]
|
|
140
|
+
|
|
141
|
+
# convert temp in units of Ha into K
|
|
142
|
+
kb = 1 #3.166811563e-6 # Ha K^-1
|
|
143
|
+
T = tau/kb
|
|
144
|
+
|
|
145
|
+
# obtain boltzman weights
|
|
146
|
+
w = fermi_weights(vals,mu,T)
|
|
147
|
+
dens = np.zeros(nx)
|
|
148
|
+
for i in range(ne):
|
|
149
|
+
for j in range(nk):
|
|
150
|
+
# print(w.shape)
|
|
151
|
+
# print(densities.shape)
|
|
152
|
+
dens += w[j]*densities[j,:]
|
|
153
|
+
Ne = np.trapezoid(dens,x)
|
|
154
|
+
|
|
155
|
+
return Ne - target_ne
|
|
156
|
+
|
|
157
|
+
return fermi_num_func
|
|
158
|
+
|
|
159
|
+
## Shifting function
|
|
160
|
+
|
|
161
|
+
def shifter(vks_FWD, vks_INV, vxc_INV):
|
|
162
|
+
"""_summary_
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
vks_FWD (ndarray): Kohn-Sham potential from forward calculation
|
|
166
|
+
vks_INV (ndarray): Exact Kohn-Sham potential from inverse calculation
|
|
167
|
+
vxc_INV (ndarray): Exact exchange-correlation potential from inverse calculation
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
_type_: _description_
|
|
171
|
+
"""
|
|
172
|
+
# shifted_ks = []
|
|
173
|
+
# shifted_xc = []
|
|
174
|
+
timpFWDKS = vks_FWD
|
|
175
|
+
timpINVKS = vks_INV
|
|
176
|
+
shift = np.mean(timpINVKS- timpFWDKS)
|
|
177
|
+
shifted_ks = (vks_INV + shift)
|
|
178
|
+
shifted_xc = (vxc_INV + shift)
|
|
179
|
+
return shifted_ks, shifted_xc
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def energy_calculators(temps, vxc_ZTA_list, vxc_LDAZTA_list, dens_list, grid_list):
|
|
183
|
+
"""_summary_
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
temps (list): list of temperatures
|
|
187
|
+
vxc_ZTA_list (list): list of exact ZTA vxc arrays
|
|
188
|
+
vxc_LDAZTA_list (list): list of approximate ZTA vxc arrays
|
|
189
|
+
dens_list (list): list of theramlized density arrays
|
|
190
|
+
grid_list (list): list of numerical grids (these should be identical but this set up allows for non identical grids)
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
_type_: _description_
|
|
194
|
+
"""
|
|
195
|
+
Exc_ZTA_list = []
|
|
196
|
+
Exc_LDAZTA_list = []
|
|
197
|
+
for i in range(len(temps)):
|
|
198
|
+
Exc_ZTA = -sp.integrate.simpson((np.diff(vxc_ZTA_list[0])) * (dens_list[i][1:]*grid_list[i][1:]), grid_list[i][1:])
|
|
199
|
+
compA = np.diff(vxc_LDAZTA_list[i])
|
|
200
|
+
compB = grid_list[i]
|
|
201
|
+
compC = dens_list[i]
|
|
202
|
+
compD = grid_list[i]
|
|
203
|
+
Exc_LDAZTA = -sp.integrate.simpson((compA)* (compB*compC)[1:],compD[1:])
|
|
204
|
+
Exc_ZTA_list.append(Exc_ZTA)
|
|
205
|
+
Exc_LDAZTA_list.append(Exc_LDAZTA)
|
|
206
|
+
return Exc_ZTA_list, Exc_LDAZTA_list
|
|
207
|
+
|
|
208
|
+
def energy_diffs(temps, Exc_ZTA_list, Exc_LDAZTA_list, print_opt:bool = False):
|
|
209
|
+
"""Calculates the difference between the Exact ZTA Exc and the LDAZTA Exc
|
|
210
|
+
This could really be abstracted to work with any functional but I will always default to saying LDA
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
temps (list): list of temperatures
|
|
214
|
+
Exc_ZTA_list (list): list of exact ZTA Exc values
|
|
215
|
+
Exc_LDAZTA_list (_type_): list of approximate ZTA Exc values
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
_type_: _description_
|
|
219
|
+
"""
|
|
220
|
+
LDA_diffs = []
|
|
221
|
+
for i in range(len(temps)):
|
|
222
|
+
xc_diff = Exc_LDAZTA_list[i] - Exc_ZTA_list[i]
|
|
223
|
+
LDA_diffs.append(xc_diff)
|
|
224
|
+
if print_opt:
|
|
225
|
+
print(f"for tau = {temps[i]}")
|
|
226
|
+
print(f"Exact ZTA E_xc = {Exc_ZTA_list[i]}")
|
|
227
|
+
print(f"LDA ZTA E_xc = {Exc_LDAZTA_list[i]}")
|
|
228
|
+
print(f"Difference due to use of LDA approximation = {LDA_diffs[i]}\n")
|
|
229
|
+
return LDA_diffs
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
### Defining reader functions
|
|
233
|
+
def get_octo_FilePaths(molecule=str, temp=str, direction=str):
|
|
234
|
+
"""
|
|
235
|
+
Reads data for the FT molecule
|
|
236
|
+
"""
|
|
237
|
+
default_preMethod_path = os.path.join('~', 'ft_inversion_paper', 'LDAZTA', molecule, 'LDA')
|
|
238
|
+
dens_path = os.path.expanduser(os.path.join(default_preMethod_path, temp, direction, 'static', 'density.y=0,z=0'))
|
|
239
|
+
vks_path = os.path.expanduser(os.path.join(default_preMethod_path, temp, direction, 'static', 'vks.y=0,z=0'))
|
|
240
|
+
vxc_path = os.path.expanduser(os.path.join(default_preMethod_path, temp, direction, 'static', 'vxc.y=0,z=0'))
|
|
241
|
+
return dens_path, vks_path, vxc_path
|
|
242
|
+
def get_octo_Data(molecule=str, temp=str, direction=str):
|
|
243
|
+
"""
|
|
244
|
+
Reads data for the FT molecule
|
|
245
|
+
"""
|
|
246
|
+
dens_path, vks_path, vxc_path = get_octo_FilePaths(molecule, temp, direction)
|
|
247
|
+
x_grid = np.loadtxt(dens_path)[:,0] # 1D grid
|
|
248
|
+
dens = np.loadtxt(dens_path)[:,1]
|
|
249
|
+
vks = np.loadtxt(vks_path)[:,1]
|
|
250
|
+
vxc = np.loadtxt(vxc_path)[:,1]
|
|
251
|
+
return x_grid, dens, vks, vxc
|
|
252
|
+
|
|
253
|
+
def get_exact_file_paths(molecule=str):
|
|
254
|
+
default_preMethod_path = os.path.join('~', 'ft_inversion_paper', 'LDAZTA', molecule, 'exact')
|
|
255
|
+
vxc_path = os.path.expanduser(os.path.join(default_preMethod_path, 'xc_potential.pkl' ))
|
|
256
|
+
vs_path = os.path.expanduser(os.path.join(default_preMethod_path, 'ks_potential.pkl' ))
|
|
257
|
+
|
|
258
|
+
return vxc_path, vs_path
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def get_exact_data(molecule=str):
|
|
262
|
+
vxc_path, vs_path = get_exact_file_paths(molecule)
|
|
263
|
+
with open(vxc_path, 'rb') as xc_file:
|
|
264
|
+
v_xc = pickle.load(xc_file)
|
|
265
|
+
with open(vs_path, 'rb') as vs_file:
|
|
266
|
+
v_s = pickle.load(vs_file)
|
|
267
|
+
|
|
268
|
+
return v_xc, v_s
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: FT_inversion_tools
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A small package containing tools needed to perform analysis for the FT inversions paper. Packaged for consistency.
|
|
5
|
+
Author-email: "Anthony R. Osborne" <anthony.r.osborne019@pm.me>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.9
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
FTI_analysis_tools.py,sha256=W2P2c3qCXpaF1TDTfb8xHFK3etNQHVMaZKtvvFsvzq8,3378
|
|
2
|
+
ZTA_analysis_tools.py,sha256=LWqrmEn6qKNFB4jmL-SMOo10C8W-f_b4Pme7J4iDW6A,8851
|
|
3
|
+
ft_inversion_tools-0.0.1.dist-info/METADATA,sha256=0amettqwXKvn5iCvQYW4k_g5tqQ4VmMI0tgkoBuCm5M,392
|
|
4
|
+
ft_inversion_tools-0.0.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
5
|
+
ft_inversion_tools-0.0.1.dist-info/top_level.txt,sha256=f0XBkiC6NINUESHV8UzHgRPj3MftHbcog-PvX9-BHhg,38
|
|
6
|
+
ft_inversion_tools-0.0.1.dist-info/RECORD,,
|