forked from WSten/ADAQ-SYM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoverlap.py
executable file
·404 lines (311 loc) · 12 KB
/
overlap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
#!/usr/bin/env python3
from vaspwfc import vaspwfc
import numpy as np
import scipy.integrate as sci
import math as m
from extract import *
from aflow_sym_python import Symmetry
from pprint import pprint
import os
import json
import ast
def calc_overlap(Coeff, gvec, Sym_op, center, settings):
"""
Calculate overlap of a wavefunction and its symmetry
transformed counterpart or Symmetry Operator Exppectation Value (SOEV).
Input:
Coeff: list of plane wave coefficients
gvec: list of g-vectors
Sym_op: Symmetry operator matrix
center: center of orbital, fixed point
settings: settings dicitonary
Returns:
overlap or SOEV
"""
C = []
C_p = []
sym_op_inv = np.linalg.inv(Sym_op)
r_diff = center - sym_op_inv.dot(center)
for i, G in enumerate(gvec):
G_R = G.dot(sym_op_inv)
#beta = G.dot(center - sym_op_inv.dot(center))
#beta = G.dot(r_diff)
#pre_factor = m.e**(2j*m.pi*beta)
#C.append(pre_factor*Coeff[i])
C.append(m.e**(2j*m.pi*G.dot(r_diff))*Coeff[i])
if G_R[0] > 0:
j = np.where(np.all(gvec == G_R, axis=1))[0][0]
C_p.append(Coeff[j].conj())
elif G_R[0] < 0 or G_R[1] < 0 or (G_R[1] == 0 and G_R[2] < 0):
j = np.where(np.all(gvec == -G_R, axis=1))[0][0]
C_p.append(Coeff[j])
else:
j = np.where(np.all(gvec == G_R, axis=1))[0][0]
C_p.append(Coeff[j].conj())
return np.array(C).dot(np.array(C_p))
def get_overlap_list(Coeff, gvec, Sym_ops, center, settings):
"""
Calculate overlap for all symmetry operations for one band/orbital.
Inputs:
Coeff: list of plane wave coefficients
gvec: list of g-vectors
Sym_ops: array with symmetry operator info,
output for get_symmetry_operators()
center: center of orbital, fixed point
settings: settings dicitonary
Returns:
list of containing:
index, symbol, axis, angle and overlap for each operator
"""
# Identity operator is trivial
symmetry_info = [[0,Sym_ops[0][0], Sym_ops[2][0], Sym_ops[3][0]]]
ov_list = [np.real_if_close(np.sum(Coeff*Coeff.conj())).tolist()]
# Loop over each symmetry operator
for i, S in enumerate(Sym_ops[1][1:]):
overlap = calc_overlap(Coeff, gvec, S, center, settings)
i +=1
ov_list.append(np.real_if_close(overlap).tolist())
symmetry_info.append([i, Sym_ops[0][i], Sym_ops[2][i], Sym_ops[3][i]])
normalizer = 1 / ov_list[0]
for i in range(len(ov_list)):
ov_list[i] = ov_list[i]*normalizer
return ov_list, symmetry_info
def get_overlaps_of_bands(wf_file, name, spin, bands, centers, PGname, Sym_ops, folder_path_out, settings):
"""
Calculate overlaps for all bands and all symmetries.
Inputs:
wf_file: string that is the path to a WAVECAR file
name: string with name (numbering) of defect
spin: 1 or 2 for spin up or down
bands: list of band indices
centers: list of orbital center of each band
Sym_ops: array with symmetry operator info,
output for get_symmetry_operators()
folder_path_out: string that is the path to output directory
settings: settings dicitonary
Returns:
list of overlap info of each band
"""
G_reduction = settings['Gvec_reduction']
gamma = settings['Gammapoint_calc']
wav = vaspwfc(wf_file, lgamma=gamma)
encut = wav._encut
encut_trunc = encut * G_reduction
Gvec, KENERGY= gvectors_and_energy(wav, force_Gamma=gamma)
#Gvec, KENERGY = truncate_gvec(Gvec, KENERGY, encut, G_reduction)
KENERGY = KENERGY[np.where(KENERGY < encut)[0]]
Gvec = Gvec[np.where(KENERGY < encut_trunc)[0]]
pprint(centers)
result = []
# Loop of the considered bands
for i, band_i in enumerate(bands):
ks = [spin,1,band_i]
Coeffs = wav.readBandCoeff(*ks, norm=True)
#Coeffs = truncate_coeffs(Coeffs, KENERGY, encut, G_reduction)
Coeffs = Coeffs[np.where(KENERGY < encut_trunc)[0]]
ov_list, symmetry_info = get_overlap_list(Coeffs, Gvec, Sym_ops, centers[i], settings)
result.append([ks,ov_list])
ov_json = {"point_group": PGname, "symmetry_operators": symmetry_info, "orbitals": [{"index": result[i][0], "overlaps": str(result[i][1])} for i in range(len(result))]}
with open(os.path.join(folder_path_out,"Overlaps_"+name+".json"), "w") as outfile:
outfile.write(json.dumps(ov_json))
return result
def truncate_gvec(Gvec, KENERGY, encut, reduction):
"""
Truncates the g-vectors by reducing the cutoff energy.
Inputs:
Gvec: list of g-vectors
KENERGY: list of energy of each g-vector
encut: cutoff energy
reduction: factor reducing encut
Returns:
truncated list of g-vectors
truncated list of g-vector energy
"""
encut_trunc = encut * reduction
KENERGY = KENERGY[np.where(KENERGY < encut)[0]]
new_Gvec = []
for i, en in enumerate(KENERGY):
if en < encut_trunc:
new_Gvec.append(Gvec[i])
#new_Gvec = Gvec[np.where(KENERGY < encut_trunc)[0]]
return np.asarray(new_Gvec, dtype=int), KENERGY
def truncate_coeffs(Coeffs, KENERGY, encut, reduction):
"""
Truncates the plane wave coefficients by reducing the cutoff energy.
Inputs:
Coeffs: list of plane wave coefficients
KENERGY: list of energy of each g-vector
encut: cutoff energy
reduction: factor reducing encut
Returns:
truncated list of coefficients
"""
encut_trunc = encut * reduction
new_coeffs = []
for i, en in enumerate(KENERGY):
if en < encut_trunc:
new_coeffs.append(Coeffs[i])
#new_coeffs = Coeffs[np.where(KENERGY < encut_trunc)[0]]
return np.array(new_coeffs)
def get_orbital_centers(wf_file, bands_by_degen, name, spin, folder_path_out, settings):
"""
Calculates the center of the orbital between the chosen bands,
degenerate states are considered together.
Input:
wf_file: filepath to WAVECAR file
bands_by_degen: bands grouped by degeneracy
name: string with name (numbering) of defect
spin: 1 or 2 for spin channel 1 or 2
folder_path_out: string that is the path to output directory
settings: settings dicitonary
Returns:
list of centers of orbitals
"""
gamma = settings['Gammapoint_calc']
grid_mult = settings['realgrid_mult']
percent = settings['percent_cutoff']
wav = vaspwfc(wf_file, lgamma=gamma)
Gvec= wav.gvectors(force_Gamma=gamma)
grid = wav._ngrid.copy() * grid_mult
centers = []
for deg_bands in bands_by_degen:
wf_array = []
for band in deg_bands:
ks = [spin,1,int(band)]
Coeffs = wav.readBandCoeff(*ks, norm=True)
realwf = wav.wfc_r(*ks, gvec=Gvec, Cg=Coeffs, ngrid=grid)
wf_array.append(realwf)
# Regular center of mass
#c = find_average_position_general(wf_array, percent)
# shift the grid so center of mass can be taken for defects close to
# supercell edges
shift = find_circular_mean_realspace_opt(wf_array, percent)
c = find_average_position_shifted(wf_array, percent, shift)
for i in range(len(deg_bands)):
centers.append(c)
c_path = os.path.join(folder_path_out,"Centers_"+name)
np.save(c_path, centers)
file = open(c_path+".txt", "w")
file.write("Band Center\n")
for i, deg_bands in enumerate(bands_by_degen):
file.write(str(deg_bands)+" "+str(centers[i])+"\n")
file.close()
return centers
def get_good_centers(name, bands, no_irr, folder_path_out):
"""
Removes bad centers from list of centers.
Inputs:
name: string with name (numbering) of defect
bands: list of band indices
no_irr: list of band indices where the center gave no irrep
folder_path_out: string that is the path to output directory
Returns:
list of centers where all centers produced an irrep
"""
c_path = os.path.join(folder_path_out,"Centers_"+name+".npy")
centers = np.load(c_path)
centers2 = centers
for band_i in no_irr:
c = centers[bands.index(band_i)]
centers2 = centers2[np.all(centers2 != c,axis=1)]
return centers2
def replace_bad_centers(name, bands, no_irr, good_centers, folder_path_out):
"""
Replaces bad centers with ones known to be good.
Inputs:
name: string with name (numbering) of defect
bands: list of band indices
no_irr: list of band indices where the center gave no irrep
good_centers: list of good centers
folder_path_out: string that is the path to output directory
Returns:
list of good centers minus the one used
new list of centers with bad ones replaced
"""
c_path = os.path.join(folder_path_out,"Centers_"+name+".npy")
centers = np.load(c_path)
for band_i in no_irr:
centers[bands.index(band_i)] = good_centers[0]
c_path2 = os.path.join(folder_path_out,"Centers_"+name)
np.save(c_path,centers)
file = open(c_path2+".txt","a+")
file.write("Bad center switched to: \n")
for band in no_irr:
file.write(str(band)+" "+str(good_centers[0])+"\n")
file.close()
return good_centers[1:], centers
def write_overlaps_to_text(overlap_array, folder_path_out, name):
"""
Writes the overlap array to a .txt file readable by humans.
Input:
overlap_array: nested numpy array with all info from overlap calculations
folder_path_out: string with path to output directory
name: string with name of
Returns:
0
"""
ov_path = os.path.join(folder_path_out,"Overlaps_"+name+".txt")
file = open(ov_path, "w+")
for band in overlap_array:
file.write(str(band[0])+"\n")
for sym in band[1]:
file.write(str(sym)+"\n")
file.write("\n")
file.close()
return 0
def write_overlaps_to_text_fancy(PGname, folder_path_out, name, settings):
"""
Writes the overlap array to a .txt file readable by humans.
Input:
PGname: name of point group
folder_path_out: string with path to output directory
name: string with name of
Returns:
0
"""
ov1 = os.path.join(folder_path_out,"Overlaps_"+name+"_S1.json")
ov2 = os.path.join(folder_path_out,"Overlaps_"+name+"_S2.json")
f1 = open(ov1,"rb")
f2 = open(ov2,"rb")
ov_array1 = json.load(f1)
ov_array2 = json.load(f2)
f1.close()
f2.close()
rounding = 3
space = 10+rounding*2
ov_out = os.path.join(folder_path_out,"Overlaps"+name+".txt")
file = open(ov_out, "w+")
ch_table, pos_vector = get_character_table(PGname,settings)
file.write("Overlaps\n")
file.write("\nPoint group: "+PGname+"\n")
sym_string = f"{'Band:':<12}"
last_sym = "1"
for sym in ch_table[0][1:]:
try:
last_sym = int(last_sym)
sym_string += f"{sym:<{space}}"*last_sym
except:
try:
int(sym)
except:
sym_string += f"{sym:<{space}}"
last_sym = sym
file.write("Spin up\n"+sym_string+"\n")
for orbital_info in ov_array1["orbitals"]:
ov_string = f"{orbital_info['index'][2]:<12}"
for overlap in ast.literal_eval(orbital_info["overlaps"]):
ov = round(np.real(overlap),rounding) + 1j*round(np.imag(overlap),rounding)
ov = str(ov).strip('(').strip(')')
ov_string += f"{ov:<{space}}"
file.write(ov_string+"\n")
file.write("\nSpin down\n"+sym_string+"\n")
for orbital_info in ov_array2["orbitals"]:
ov_string = f"{orbital_info['index'][2]:<12}"
for overlap in ast.literal_eval(orbital_info["overlaps"]):
ov = round(np.real(overlap),rounding) + 1j*round(np.imag(overlap),rounding)
ov = str(ov).strip('(').strip(')')
ov_string += f"{ov:<{space}}"
file.write(ov_string+"\n")
return 0
if __name__ == "__main__":
0