-
Ruocheng Han authoredRuocheng Han authored
rho_Becke_grid.py 9.64 KiB
import numpy as np
import os
import sys
import h5py
import itertools
from mpl_toolkits.mplot3d import Axes3D
def quant_fill():
quant = np.empty((35,3))
quant[0,0]=0;quant[0,1]=0;quant[0,2]=0;
quant[1,0]=1;quant[1,1]=0;quant[1,2]=0;
quant[2,0]=0;quant[2,1]=1;quant[2,2]=0;
quant[3,0]=0;quant[3,1]=0;quant[3,2]=1;
quant[4,0]=2;quant[4,1]=0;quant[4,2]=0;
quant[5,0]=0;quant[5,1]=2;quant[5,2]=0;
quant[6,0]=0;quant[6,1]=0;quant[6,2]=2;
quant[7,0]=1;quant[7,1]=1;quant[7,2]=0;
quant[8,0]=1;quant[8,1]=0;quant[8,2]=1;
quant[9,0]=0;quant[9,1]=1;quant[9,2]=1;
quant[10,0]=3;quant[10,1]=0;quant[10,2]=0;
quant[11,0]=0;quant[11,1]=3;quant[11,2]=0;
quant[12,0]=0;quant[12,1]=0;quant[12,2]=3;
quant[13,0]=2;quant[13,1]=1;quant[13,2]=0;
quant[14,0]=2;quant[14,1]=0;quant[14,2]=1;
quant[15,0]=0;quant[15,1]=2;quant[15,2]=1;
quant[16,0]=1;quant[16,1]=2;quant[16,2]=0;
quant[17,0]=1;quant[17,1]=0;quant[17,2]=2;
quant[18,0]=0;quant[18,1]=1;quant[18,2]=2;
quant[19,0]=1;quant[19,1]=1;quant[19,2]=1;
quant[20,0]=4;quant[20,1]=0;quant[20,2]=0;
quant[21,0]=0;quant[21,1]=4;quant[21,2]=0;
quant[22,0]=0;quant[22,1]=0;quant[22,2]=4;
quant[23,0]=3;quant[23,1]=1;quant[23,2]=0;
quant[24,0]=3;quant[24,1]=0;quant[24,2]=1;
quant[25,0]=1;quant[25,1]=3;quant[25,2]=0;
quant[26,0]=0;quant[26,1]=3;quant[26,2]=1;
quant[27,0]=1;quant[27,1]=0;quant[27,2]=3;
quant[28,0]=0;quant[28,1]=1;quant[28,2]=3;
quant[29,0]=2;quant[29,1]=2;quant[29,2]=0;
quant[30,0]=2;quant[30,1]=0;quant[30,2]=2;
quant[31,0]=0;quant[31,1]=2;quant[31,2]=2;
quant[32,0]=2;quant[32,1]=1;quant[32,2]=1;
quant[33,0]=1;quant[33,1]=2;quant[33,2]=1;
quant[34,0]=1;quant[34,1]=1;quant[34,2]=2;
return quant
def calcu_prt_power(num_grid, dpos, max_nlm):
# 3*nlm(power)*num_grid
prt_power = np.ones(([3, max_nlm+1] + [num_grid]))
for a in range(3):
dpos_a = dpos[:,a]
for nlm in range(1, max_nlm+1): # nlm=0 are all initiated as ones
prt_power[a,nlm] = np.power(dpos_a, nlm)
return prt_power
def calcu_prt_exp(num_grid, dpos, exp_c):
# len(exp_c)*num_grid
prt_exp = np.empty(([len(exp_c)] + [num_grid]))
dpos_norm = np.linalg.norm(dpos, axis=-1)
for ei in range(len(exp_c)):
prt_exp[ei] = np.exp(-exp_c[ei]*np.power(dpos_norm,2))
return prt_exp
def calcu_prt(grid, num_grid, quant, pos_c, typ_c, exp_c):
dpos = np.subtract(grid, pos_c)
dpos[dpos == 0] = 1e-8
# calculate exponent term for pos_c
prt_exp = calcu_prt_exp(num_grid, dpos, exp_c)
# precalculate all possible polynomial terms for pos_c
max_nlm = max([q for t in typ_c for q in quant[t]])
prt_power = calcu_prt_power(num_grid, dpos, max_nlm)
# calculate primitives
prt_c = np.empty(([len(typ_c)] + [num_grid]))
for ti in range(len(typ_c)):
t = typ_c[ti]
prt_c[ti] = prt_power[0,quant[t,0]] * prt_power[1,quant[t,1]] * prt_power[2,quant[t,2]] * prt_exp[ti]
# calculate gradients of primitives (grdrho(x)=[nx/(xi-xA)-2epi*(xi-xA)]*rho)
grdprt_c = np.empty(([len(typ_c),3] + [num_grid]))
grd = np.empty(([len(typ_c),3] + [num_grid]))
for dim in range(3):
for ti in range(len(typ_c)):
t = typ_c[ti]
tmp = np.divide(quant[t,dim], dpos[:,dim])
grd[ti,dim] = np.subtract(tmp, 2 * exp_c[ti] * dpos[:,dim])
grdprt_c[ti,dim] = grd[ti,dim] * prt_c[ti]
'''
# calculate sec gradients of primitives grd2rho(x)
grd2prt_c = np.empty(([len(typ_c),3,3] + [num_grid]))
for dim1 in range(3):
for dim2 in range(3):
for ti in range(len(typ_c)):
t = typ_c[ti]
tmp = -np.divide(quant[t,dim], np.power(dpos[:,dim],2))
if dim1 == dim2:
grd2prt_c[ti,dim1,dim2] = np.add(np.subtract(tmp, 2 * exp_c[ti]) * prt_c[ti], grd[ti,dim2] * grdprt_c[ti,dim1])
else:
grd2prt_c[ti,dim1,dim2] = grd[ti,dim2] * grdprt_c[ti,dim1]
'''
return prt_c, grdprt_c #, grd2prt_c
def sel_shell(unoccmo, hf_occ, num_orb, sel_orb, noe):
if sel_orb == 'all':
mat = np.ones((unoccmo))
else:
sel_orb = int(sel_orb)
mat = np.zeros((unoccmo))
mat[hf_occ-sel_orb:] = np.ones((sel_orb+unoccmo-hf_occ))
'''
for i in range(unoccmo):
c = 0
for j in range(unoccmo, num_orb):
c += 1 / (noe[j] - noe[i])
mat[i] *= c
'''
#mat = mat / (noe[unoccmo] - noe[unoccmo-1])
print(mat)
return mat
def calcu_grid(fwfn, grid, sel_orb, hf_occ):
num_grid = len(grid)
# load wave functions from h5py
with h5py.File(fwfn, 'r') as hf:
typ_orb, num_orb, num_prt, num_nuc = hf['BASIC'][:]
pos = hf['POS'][:]
cassign = hf['CASSIGN'][:]
tassign = hf['TASSIGN'][:]
exp = hf['EXP'][:]
noon = hf['NOON'][:]
noe = hf['NOE'][:]
nocoef = hf['NOCOEF'][:]
# assign positions to primitives -> a nested center-type list
# e.g. [1,1,1,1,2,2,2] [1,1,2,3,1,1,2] -> [[1,1,2,3],[1,1,2]]
# same with nested center-exponet list
ct_list = [[] for _ in range(len(set(cassign)))]
ce_list = [[] for _ in range(len(set(cassign)))]
#print(len(cassign))
#print(len(tassign))
for i in range(len(cassign)):
ct_list[cassign[i]-1].append(tassign[i]-1) # tassign[i]-1 to correspond to quant_fill()
ce_list[cassign[i]-1].append(exp[i])
# fill the type with quantum number -> 35 * [n,m,l]
quant = quant_fill().astype(int)
# check the nonzero occ
if np.min(noon) == 0:
unoccmo = next(list(noon).index(o) for o in list(noon) if o==0)
else:
unoccmo = num_orb
# select only the shell
shell = sel_shell(unoccmo, hf_occ, num_orb, sel_orb, noe)
# calculate for every center(atom) the primitive (dpd: atom)
prt = np.empty(([0] + [num_grid]), dtype=np.float32) # initiate a matrix with unknown dim of concatenate axis for center(atom)
grdprt = np.empty(([0,3] + [num_grid]), dtype=np.float32)
#grd2prt = np.empty(([0,3,3] + [num_grid]))
for c in range(num_nuc):
#prt_c, grdprt_c, grd2prt_c = calcu_prt(grid, num_grid, quant, pos[c], ct_list[c], ce_list[c]) # this is primitives per atom
prt_c, grdprt_c = calcu_prt(grid, num_grid, quant, pos[c], ct_list[c], ce_list[c])
#prt, grdprt, grd2prt = np.append(prt, prt_c, axis=0), np.append(grdprt, grdprt_c, axis=0), np.append(grd2prt, grd2prt_c, axis=0)
prt, grdprt = np.append(prt, prt_c, axis=0), np.append(grdprt, grdprt_c, axis=0)
np.save('prt.npy', prt)
np.save('grdprt.npy', grdprt)
print('Finish prt and grdprt calculations!')
# summation of the primitives based on nocoef and no
# prt in dimension num_prt * num_grid
# grdprt in dimension num_prt * 3 * num_grid
nowfn = np.empty([num_orb] + [num_grid])
norho = np.empty([unoccmo] + [num_grid])
nokin = np.empty([unoccmo] + [num_grid])
nogrdrho = np.empty([unoccmo,3] + [num_grid])
nogrd2rho = np.empty([unoccmo,3,3] + [num_grid])
# for nonzero occupied no
for n in range(unoccmo):
# rho & wfn #
prtwfn = np.multiply(nocoef[n][:,np.newaxis], prt)
nowfn[n] = np.sum(prtwfn, axis=0)
norho[n] = shell[n] * noon[n] * np.power(nowfn[n], 2)
# grd #
grdprtwfn = np.multiply(nocoef[n][:,np.newaxis,np.newaxis], grdprt)
nogrdrho[n] = 2 * shell[n] * noon[n] * (np.multiply(np.sum(prtwfn, axis=0), np.sum(grdprtwfn, axis=0)))
# kin #
nokin[n] = shell[n] * noon[n] * np.sum(np.power(np.sum(grdprtwfn, axis=0), 2), axis=0)
'''
# grd2 #
grd2prtwfn = np.multiply(nocoef[n][:,np.newaxis,np.newaxis,np.newaxis], grd2prt)
tmp1 = np.multiply(np.sum(prtwfn, axis=0), np.sum(grd2prtwfn, axis=0))
grdwfn = np.sum(grdprtwfn, axis=0)
tmp2 = np.empty([3,3] + [num_grid])
for dim1 in range(3):
for dim2 in range(3):
tmp2[dim1,dim2] = grdwfn[dim1] * grdwfn[dim2]
nogrd2rho[n] = 2 * shell[n] * noon[n] * np.add(tmp1, tmp2)
'''
# for zero occupied no
for n in range(unoccmo, num_orb):
# wfn #
prtwfn = np.multiply(nocoef[n][:,np.newaxis], prt)
nowfn[n] = np.sum(prtwfn, axis=0)
del prtwfn
del grdprtwfn
#del grd2prtwfn
rho = np.sum(norho, axis=0)
del norho
grdrho = np.sum(nogrdrho, axis=0)
del nogrdrho
kin = np.sum(nokin, axis=0)
del nokin
grd2rho = np.sum(nogrd2rho, axis=0)
del nogrd2rho
nrm_grdrho = np.linalg.norm(grdrho, axis=0)
# calculate grd2rho eigen values
dig_grd2rho = np.empty([num_grid] + [3])
for i in range(num_grid):
w, _ = np.linalg.eig(grd2rho[:,:,i])
dig_grd2rho[i] = np.sort(w)
'''
rg_grdrho = []
for i in range(num_grid):
rg_grdrho.append(grdrho[:,i])
rg_grdrho = np.array(rg_grdrho)
'''
# save grid points and their rho, gradrho, grad2rho
np.save('rho-' + sys.argv[1].split('/')[-1].split('.')[0] + '.npy', rho)
np.save('nrmgrdrho-' + sys.argv[1].split('/')[-1].split('.')[0] + '.npy', nrm_grdrho)
np.save('kin-' + sys.argv[1].split('/')[-1].split('.')[0] + '.npy', kin)
np.save('diglaprho-' + sys.argv[1].split('/')[-1].split('.')[0] + '.npy', dig_grd2rho)
np.savetxt('rho.dat', rho)
np.savetxt('nrmgrdrho.dat', nrm_grdrho)
np.savetxt('kin.dat', kin)
np.savetxt('diglaprho.dat', dig_grd2rho)
# plot 3d scattering of grid
# plot3d(rg_grid)
return rho, nowfn.T
def main():
fwfn = sys.argv[1]
fgrid = sys.argv[2]
fwgt = sys.argv[3]
sel_orb = sys.argv[4]
hf_occ = int(sys.argv[5]) # in casci cases, we need to know lumo from hf occupation
with h5py.File(fwfn, 'r') as hf:
_, _, _, num_nuc = hf['BASIC'][:]
# load grids and weights
grid = np.load(fgrid)
wgt = np.load(fwgt)
# calculate rho grad lap on each grid
rho, wfn = calcu_grid(fwfn, grid, sel_orb, hf_occ)
# sum up all of them based on weight
wrho = np.sum(np.multiply(wgt, rho))
print('Integrated rho of of system' + ': ' + str(wrho))
# save grid points and their NO wfn
np.savez(sys.argv[1].split('/')[-1].split('.')[0] + '.npz', GRID=grid, WFN=wfn, WGT=wgt)
if __name__ == "__main__":
main()