10
0
mirror of https://github.com/QuantumPackage/qp2.git synced 2024-07-08 20:33:56 +02:00
QuantumPackage/src/utils_complex/MolPyscfToQPkpts.py
Kevin Gasperich 02c6539daa fixed problem with iterating over unique 2-electron integrals
should loop over union of two sets of integrals:
set 1:
  i<=k
  j<=l
  ik<=jl
set 2:
  i>k
  j<l
  ik<=jl

looping over kpts in same way is incorrect
here I've relaxed the constraints over kpt indices, while keeping those over orbital indices
There is probably a more efficient way to do this where we have more kpt constraints and additional logic in orbital loops
2020-02-18 14:11:22 -06:00

1137 lines
44 KiB
Python

import numpy as np
from functools import reduce
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
@memoize
def idx2_tri(iijj):
'''
iijj should be a 2-tuple
return triangular compound index for (0-indexed counting)
'''
ij1=min(iijj)
ij2=max(iijj)
return ij1+(ij2*(ij2+1))//2
# return ij1+(ij2*(ij2-1))//2
def pad(arr_in,outshape):
arr_out = np.zeros(outshape,dtype=np.complex128)
dataslice = tuple(slice(0,arr_in.shape[dim]) for dim in range(len(outshape)))
arr_out[dataslice] = arr_in
return arr_out
def makesq(vlist,n1,n2):
'''
make hermitian matrices of size (n2 x n2) from from lower triangles
vlist is n1 lower triangles in flattened form
given: ([a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t],2,4)
output a 2x4x4 array, where each 4x4 is the square constructed from the lower triangle
[
[
[a b* d* g*]
[b c e* h*]
[d e f i*]
[g h i j ]
],
[
[k l* n* q*]
[l m o* r*]
[n o p s*]
[q r s t ]
]
]
'''
out=np.zeros([n1,n2,n2],dtype=np.complex128)
n0 = vlist.shape[0]
lmask=np.tri(n2,dtype=bool)
for i in range(n0):
out[i][lmask] = vlist[i].conj()
out2=out.transpose([0,2,1])
for i in range(n0):
out2[i][lmask] = vlist[i]
return out2
def makesq3(vlist,n2):
'''
make hermitian matrices of size (n2 x n2) from from lower triangles
vlist is n1 lower triangles in flattened form
given: ([a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t],2,4)
output a 2x4x4 array, where each 4x4 is the square constructed from the lower triangle
[
[
[a b* d* g*]
[b c e* h*]
[d e f i*]
[g h i j ]
],
[
[k l* n* q*]
[l m o* r*]
[n o p s*]
[q r s t ]
]
]
'''
n0 = vlist.shape[0]
out=np.zeros([n0,n2,n2],dtype=np.complex128)
lmask=np.tri(n2,dtype=bool)
for i in range(n0):
out[i][lmask] = vlist[i].conj()
out2=out.transpose([0,2,1])
for i in range(n0):
out2[i][lmask] = vlist[i]
return out2
def makesq2(vlist,n1,n2):
out=np.zeros([n1,n2,n2],dtype=np.complex128)
lmask=np.tri(n2,dtype=bool)
tmp=np.zeros([n2,n2],dtype=np.complex128)
tmp2=np.zeros([n2,n2],dtype=np.complex128)
for i in range(n1):
tmp[lmask] = vlist[i].conj()
tmp2=tmp.T
tmp2[lmask] = vlist[i]
out[i] = tmp2.copy()
return out
def get_phase(cell, kpts, kmesh=None):
'''
The unitary transformation that transforms the supercell basis k-mesh
adapted basis.
'''
from pyscf.pbc import tools
from pyscf import lib
latt_vec = cell.lattice_vectors()
if kmesh is None:
# Guess kmesh
scaled_k = cell.get_scaled_kpts(kpts).round(8)
kmesh = (len(np.unique(scaled_k[:,0])),
len(np.unique(scaled_k[:,1])),
len(np.unique(scaled_k[:,2])))
R_rel_a = np.arange(kmesh[0])
R_rel_b = np.arange(kmesh[1])
R_rel_c = np.arange(kmesh[2])
R_vec_rel = lib.cartesian_prod((R_rel_a, R_rel_b, R_rel_c))
R_vec_abs = np.einsum('nu, uv -> nv', R_vec_rel, latt_vec)
NR = len(R_vec_abs)
phase = np.exp(1j*np.einsum('Ru, ku -> Rk', R_vec_abs, kpts))
phase /= np.sqrt(NR) # normalization in supercell
# R_rel_mesh has to be construct exactly same to the Ts in super_cell function
scell = tools.super_cell(cell, kmesh)
return scell, phase
def mo_k2gamma(cell, mo_energy, mo_coeff, kpts, kmesh=None):
'''
Transform MOs in Kpoints to the equivalents supercell
'''
from pyscf import lib
import scipy.linalg as la
scell, phase = get_phase(cell, kpts, kmesh)
E_g = np.hstack(mo_energy)
C_k = np.asarray(mo_coeff)
Nk, Nao, Nmo = C_k.shape
NR = phase.shape[0]
# Transform AO indices
C_gamma = np.einsum('Rk, kum -> Rukm', phase, C_k)
C_gamma = C_gamma.reshape(Nao*NR, Nk*Nmo)
E_sort_idx = np.argsort(E_g)
E_g = E_g[E_sort_idx]
C_gamma = C_gamma[:,E_sort_idx]
s = scell.pbc_intor('int1e_ovlp')
assert(abs(reduce(np.dot, (C_gamma.conj().T, s, C_gamma))
- np.eye(Nmo*Nk)).max() < 1e-7)
# Transform MO indices
E_k_degen = abs(E_g[1:] - E_g[:-1]).max() < 1e-5
if np.any(E_k_degen):
degen_mask = np.append(False, E_k_degen) | np.append(E_k_degen, False)
shift = min(E_g[degen_mask]) - .1
f = np.dot(C_gamma[:,degen_mask] * (E_g[degen_mask] - shift),
C_gamma[:,degen_mask].conj().T)
assert(abs(f.imag).max() < 1e-5)
e, na_orb = la.eigh(f.real, s, type=2)
C_gamma[:,degen_mask] = na_orb[:, e>0]
if abs(C_gamma.imag).max() < 1e-7:
print('!Warning Some complexe pollutions in MOs are present')
C_gamma = C_gamma.real
if abs(reduce(np.dot, (C_gamma.conj().T, s, C_gamma)) - np.eye(Nmo*Nk)).max() < 1e-7:
print('!Warning Some complexe pollutions in MOs are present')
s_k = cell.pbc_intor('int1e_ovlp', kpts=kpts)
# overlap between k-point unitcell and gamma-point supercell
s_k_g = np.einsum('kuv,Rk->kuRv', s_k, phase.conj()).reshape(Nk,Nao,NR*Nao)
# The unitary transformation from k-adapted orbitals to gamma-point orbitals
mo_phase = lib.einsum('kum,kuv,vi->kmi', C_k.conj(), s_k_g, C_gamma)
return mo_phase
def qp2rename():
import shutil
qp2names={}
qp2names['mo_coef_complex'] = 'C.qp'
qp2names['bielec_ao_complex'] = 'W.qp'
qp2names['kinetic_ao_complex'] = 'T.qp'
qp2names['ne_ao_complex'] = 'V.qp'
qp2names['overlap_ao_complex'] = 'S.qp'
for old,new in qp2names.items():
shutil.move(old,new)
shutil.copy('e_nuc','E.qp')
def pyscf2QP(cell,mf, kpts, kmesh=None, cas_idx=None, int_threshold = 1E-8,
print_ao_ints_bi=False,
print_mo_ints_bi=False,
print_ao_ints_df=True,
print_mo_ints_df=False,
print_ao_ints_mono=True,
print_mo_ints_mono=False):
'''
kpts = List of kpoints coordinates. Cannot be null, for gamma is other script
kmesh = Mesh of kpoints (optional)
cas_idx = List of active MOs. If not specified all MOs are actives
int_threshold = The integral will be not printed in they are bellow that
'''
from pyscf.pbc import ao2mo
from pyscf.pbc import tools
from pyscf.pbc.gto import ecp
import h5py
mo_coef_threshold = int_threshold
ovlp_threshold = int_threshold
kin_threshold = int_threshold
ne_threshold = int_threshold
bielec_int_threshold = int_threshold
natom = len(cell.atom_coords())
print('n_atom per kpt', natom)
print('num_elec per kpt', cell.nelectron)
mo_coeff = mf.mo_coeff
# Mo_coeff actif
mo_k = np.array([c[:,cas_idx] for c in mo_coeff] if cas_idx is not None else mo_coeff)
e_k = np.array([e[cas_idx] for e in mf.mo_energy] if cas_idx is not None else mf.mo_energy)
Nk, nao, nmo = mo_k.shape
print("n Kpts", Nk)
print("n active Mos per kpt", nmo)
print("n AOs per kpt", nao)
naux = mf.with_df.auxcell.nao
print("n df fitting functions", naux)
with open('num_df','w') as f:
f.write(str(naux))
# Write all the parameter need to creat a dummy EZFIO folder who will containt the integral after.
# More an implentation detail than a real thing
with open('param','w') as f:
# Note the use of nmo_tot
f.write(' '.join(map(str,(cell.nelectron*Nk, Nk*nmo, natom*Nk))))
with open('num_ao','w') as f:
f.write(str(nao*Nk))
with open('kpt_num','w') as f:
f.write(str(Nk))
# _
# |\ | _ | _ _. ._ |_) _ ._ | _ o _ ._
# | \| |_| (_ | (/_ (_| | | \ (/_ |_) |_| | _> | (_) | |
# |
#Total energy shift due to Ewald probe charge = -1/2 * Nelec*madelung/cell.vol =
shift = tools.pbc.madelung(cell, kpts)*cell.nelectron * -.5
e_nuc = (cell.energy_nuc() + shift)*Nk
print('nucl_repul', e_nuc)
with open('e_nuc','w') as f:
f.write(str(e_nuc))
# __ __ _
# |\/| | | | _ _ |_ _
# | | |__| |__ (_) (/_ | _>
#
with open('mo_coef_complex','w') as outfile:
c_kpts = np.reshape(mo_k,(Nk,nao,nmo))
for ik in range(Nk):
shift1=ik*nao+1
shift2=ik*nmo+1
for i in range(nao):
for j in range(nmo):
cij = c_kpts[ik,i,j]
if abs(cij) > mo_coef_threshold:
outfile.write('%s %s %s %s\n' % (i+shift1, j+shift2, cij.real, cij.imag))
# ___
# | ._ _|_ _ _ ._ _. | _ |\/| _ ._ _
# _|_ | | |_ (/_ (_| | (_| | _> | | (_) | | (_)
# _|
if mf.cell.pseudo:
v_kpts_ao = np.reshape(mf.with_df.get_pp(kpts=kpts),(Nk,nao,nao))
else:
v_kpts_ao = np.reshape(mf.with_df.get_nuc(kpts=kpts),(Nk,nao,nao))
if len(cell._ecpbas) > 0:
v_kpts_ao += np.reshape(ecp.ecp_int(cell, kpts),(Nk,nao,nao))
ne_ao = ('ne',v_kpts_ao,ne_threshold)
ovlp_ao = ('overlap',np.reshape(mf.get_ovlp(cell=cell,kpts=kpts),(Nk,nao,nao)),ovlp_threshold)
kin_ao = ('kinetic',np.reshape(cell.pbc_intor('int1e_kin',1,1,kpts=kpts),(Nk,nao,nao)),kin_threshold)
for name, intval_kpts_ao, thresh in (ne_ao, ovlp_ao, kin_ao):
if print_ao_ints_mono:
with open('%s_ao_complex' % name,'w') as outfile:
for ik in range(Nk):
shift=ik*nao+1
for i in range(nao):
for j in range(i,nao):
int_ij = intval_kpts_ao[ik,i,j]
if abs(int_ij) > thresh:
outfile.write('%s %s %s %s\n' % (i+shift, j+shift, int_ij.real, int_ij.imag))
if print_mo_ints_mono:
intval_kpts_mo = np.einsum('kim,kij,kjn->kmn',mo_k.conj(),intval_kpts_ao,mo_k)
with open('%s_mo_complex' % name,'w') as outfile:
for ik in range(Nk):
shift=ik*nmo+1
for i in range(nmo):
for j in range(i,nmo):
int_ij = intval_kpts_mo[ik,i,j]
if abs(int_ij) > thresh:
outfile.write('%s %s %s %s\n' % (i+shift, j+shift, int_ij.real, int_ij.imag))
# ___ _
# | ._ _|_ _ _ ._ _. | _ |_) o
# _|_ | | |_ (/_ (_| | (_| | _> |_) |
# _|
#
kconserv = tools.get_kconserv(cell, kpts)
with open('kconserv_complex','w') as outfile:
for a in range(Nk):
for b in range(Nk):
for c in range(Nk):
d = kconserv[a,b,c]
outfile.write('%s %s %s %s\n' % (a+1,c+1,b+1,d+1))
intfile=h5py.File(mf.with_df._cderi,'r')
j3c = intfile.get('j3c')
naosq = nao*nao
naotri = (nao*(nao+1))//2
j3ckeys = list(j3c.keys())
j3ckeys.sort(key=lambda strkey:int(strkey))
# in new(?) version of PySCF, there is an extra layer of groups before the datasets
# datasets used to be [/j3c/0, /j3c/1, /j3c/2, ...]
# datasets now are [/j3c/0/0, /j3c/1/0, /j3c/2/0, ...]
j3clist = [j3c.get(i+'/0') for i in j3ckeys]
if j3clist==[None]*len(j3clist):
# if using older version, stop before last level
j3clist = [j3c.get(i) for i in j3ckeys]
nkinvsq = 1./np.sqrt(Nk)
# dimensions are (kikj,iaux,jao,kao), where kikj is compound index of kpts i and j
# output dimensions should be reversed (nao, nao, naux, nkptpairs)
j3arr=np.array([(i.value.reshape([-1,nao,nao]) if (i.shape[1] == naosq) else makesq3(i.value,nao)) * nkinvsq for i in j3clist])
nkpt_pairs = j3arr.shape[0]
if print_ao_ints_df:
with open('df_ao_integral_array','w') as outfile:
pass
with open('df_ao_integral_array','a') as outfile:
for k,kpt_pair in enumerate(j3arr):
for iaux,dfbasfunc in enumerate(kpt_pair):
for i,i0 in enumerate(dfbasfunc):
for j,v in enumerate(i0):
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (i+1,j+1,iaux+1,k+1,v.real,v.imag))
if print_mo_ints_df:
kpair_list=[]
for i in range(Nk):
for j in range(Nk):
if(i>=j):
kpair_list.append((i,j,idx2_tri((i,j))))
j3mo = np.array([np.einsum('mij,ik,jl->mkl',j3arr[kij],mo_k[ki].conj(),mo_k[kj]) for ki,kj,kij in kpair_list])
with open('df_mo_integral_array','w') as outfile:
pass
with open('df_mo_integral_array','a') as outfile:
for k,kpt_pair in enumerate(j3mo):
for iaux,dfbasfunc in enumerate(kpt_pair):
for i,i0 in enumerate(dfbasfunc):
for j,v in enumerate(i0):
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (i+1,j+1,iaux+1,k+1,v.real,v.imag))
# eri_4d_ao = np.zeros((Nk,nao,Nk,nao,Nk,nao,Nk,nao), dtype=np.complex)
# for d, kd in enumerate(kpts):
# for c, kc in enumerate(kpts):
# if c > d: break
# idx2_cd = idx2_tri(c,d)
# for b, kb in enumerate(kpts):
# if b > d: break
# a = kconserv[b,c,d]
# if idx2_tri(a,b) > idx2_cd: continue
# if ((c==d) and (a>b)): continue
# ka = kpts[a]
# v = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
# v *= 1./Nk
# eri_4d_ao[a,:,b,:,c,:,d] = v
#
# eri_4d_ao = eri_4d_ao.reshape([Nk*nao]*4)
if (print_ao_ints_bi or print_mo_ints_bi):
if print_ao_ints_bi:
with open('bielec_ao_complex','w') as outfile:
pass
if print_mo_ints_bi:
with open('bielec_mo_complex','w') as outfile:
pass
for d, kd in enumerate(kpts):
for c, kc in enumerate(kpts):
if c > d: break
idx2_cd = idx2_tri((c,d))
for b, kb in enumerate(kpts):
if b > d: break
a = kconserv[b,c,d]
if idx2_tri((a,b)) > idx2_cd: continue
if ((c==d) and (a>b)): continue
ka = kpts[a]
if print_ao_ints_bi:
with open('bielec_ao_complex','a') as outfile:
eri_4d_ao_kpt = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
eri_4d_ao_kpt *= 1./Nk
for l in range(nao):
ll=l+d*nao
for j in range(nao):
jj=j+c*nao
if jj>ll: break
idx2_jjll = idx2_tri((jj,ll))
for k in range(nao):
kk=k+b*nao
if kk>ll: break
for i in range(nao):
ii=i+a*nao
if idx2_tri((ii,kk)) > idx2_jjll: break
if ((jj==ll) and (ii>kk)): break
v=eri_4d_ao_kpt[i,k,j,l]
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (ii+1,jj+1,kk+1,ll+1,v.real,v.imag))
if print_mo_ints_bi:
with open('bielec_mo_complex','a') as outfile:
eri_4d_mo_kpt = mf.with_df.ao2mo([mo_k[a], mo_k[b], mo_k[c], mo_k[d]],
[ka,kb,kc,kd],compact=False).reshape((nmo,)*4)
eri_4d_mo_kpt *= 1./Nk
for l in range(nmo):
ll=l+d*nmo
for j in range(nmo):
jj=j+c*nmo
if jj>ll: break
idx2_jjll = idx2_tri((jj,ll))
for k in range(nmo):
kk=k+b*nmo
if kk>ll: break
for i in range(nmo):
ii=i+a*nmo
if idx2_tri((ii,kk)) > idx2_jjll: break
if ((jj==ll) and (ii>kk)): break
v=eri_4d_mo_kpt[i,k,j,l]
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (ii+1,jj+1,kk+1,ll+1,v.real,v.imag))
def testprintbi(cell,mf, kpts, kmesh=None, cas_idx=None, int_threshold = 1E-8):
'''
kpts = List of kpoints coordinates. Cannot be null, for gamma is other script
kmesh = Mesh of kpoints (optional)
cas_idx = List of active MOs. If not specified all MOs are actives
int_threshold = The integral will be not printed in they are bellow that
'''
from pyscf.pbc import ao2mo
from pyscf.pbc import tools
from pyscf.pbc.gto import ecp
from pyscf.data import nist
import h5py
import scipy
bielec_int_threshold = int_threshold
natom = cell.natm
nelec = cell.nelectron
neleca,nelecb = cell.nelec
atom_xyz = mf.cell.atom_coords()
if not(mf.cell.unit.startswith(('B','b','au','AU'))):
atom_xyz /= nist.BOHR # always convert to au
strtype=h5py.special_dtype(vlen=str)
atom_dset=qph5.create_dataset('nuclei/nucl_label',(natom,),dtype=strtype)
for i in range(natom):
atom_dset[i] = mf.cell.atom_pure_symbol(i)
qph5.create_dataset('nuclei/nucl_coord',data=atom_xyz)
qph5.create_dataset('nuclei/nucl_charge',data=mf.cell.atom_charges())
print('n_atom per kpt', natom)
print('num_elec per kpt', nelec)
mo_coeff = mf.mo_coeff
# Mo_coeff actif
mo_k = np.array([c[:,cas_idx] for c in mo_coeff] if cas_idx is not None else mo_coeff)
e_k = np.array([e[cas_idx] for e in mf.mo_energy] if cas_idx is not None else mf.mo_energy)
Nk, nao, nmo = mo_k.shape
print("n Kpts", Nk)
print("n active Mos per kpt", nmo)
print("n AOs per kpt", nao)
naux = mf.with_df.auxcell.nao
print("n df fitting functions", naux)
#in old version: param << nelec*Nk, nmo*Nk, natom*Nk
# ___ _
# | ._ _|_ _ _ ._ _. | _ |_) o
# _|_ | | |_ (/_ (_| | (_| | _> |_) |
# _|
#
kconserv = tools.get_kconserv(cell, kpts)
qph5.create_dataset('nuclei/kconserv',data=np.transpose(kconserv+1,(0,2,1)))
kcon_test = np.zeros((Nk,Nk,Nk),dtype=int)
for a in range(Nk):
for b in range(Nk):
for c in range(Nk):
kcon_test[a,c,b] = kconserv[a,b,c]+1
qph5.create_dataset('nuclei/kconserv_test',data=kcon_test)
with open('K.qp','w') as outfile:
for a in range(Nk):
for b in range(Nk):
for c in range(Nk):
d = kconserv[a,b,c]
outfile.write('%s %s %s %s\n' % (a+1,c+1,b+1,d+1))
intfile=h5py.File(mf.with_df._cderi,'r')
j3c = intfile.get('j3c')
naosq = nao*nao
naotri = (nao*(nao+1))//2
j3ckeys = list(j3c.keys())
j3ckeys.sort(key=lambda strkey:int(strkey))
# in new(?) version of PySCF, there is an extra layer of groups before the datasets
# datasets used to be [/j3c/0, /j3c/1, /j3c/2, ...]
# datasets now are [/j3c/0/0, /j3c/1/0, /j3c/2/0, ...]
j3clist = [j3c.get(i+'/0') for i in j3ckeys]
if j3clist==[None]*len(j3clist):
# if using older version, stop before last level
j3clist = [j3c.get(i) for i in j3ckeys]
nkinvsq = 1./np.sqrt(Nk)
# dimensions are (kikj,iaux,jao,kao), where kikj is compound index of kpts i and j
# output dimensions should be reversed (nao, nao, naux, nkptpairs)
j3arr=np.array([(i.value.reshape([-1,nao,nao]) if (i.shape[1] == naosq) else makesq3(i.value,nao)) * nkinvsq for i in j3clist])
nkpt_pairs = j3arr.shape[0]
df_ao_tmp = np.zeros((nao,nao,naux,nkpt_pairs),dtype=np.complex128)
if print_ao_ints_df:
with open('D.qp','w') as outfile:
pass
with open('D.qp','a') as outfile:
for k,kpt_pair in enumerate(j3arr):
for iaux,dfbasfunc in enumerate(kpt_pair):
for i,i0 in enumerate(dfbasfunc):
for j,v in enumerate(i0):
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (i+1,j+1,iaux+1,k+1,v.real,v.imag))
df_ao_tmp[i,j,iaux,k]=v
qph5.create_dataset('ao_two_e_ints/df_ao_integrals_real',data=df_ao_tmp.real)
qph5.create_dataset('ao_two_e_ints/df_ao_integrals_imag',data=df_ao_tmp.imag)
if print_mo_ints_df:
kpair_list=[]
for i in range(Nk):
for j in range(Nk):
if(i>=j):
kpair_list.append((i,j,idx2_tri((i,j))))
j3mo = np.array([np.einsum('mij,ik,jl->mkl',j3arr[kij],mo_k[ki].conj(),mo_k[kj]) for ki,kj,kij in kpair_list])
df_mo_tmp = np.zeros((nmo,nmo,naux,nkpt_pairs),dtype=np.complex128)
with open('D_mo.qp','w') as outfile:
pass
with open('D_mo.qp','a') as outfile:
for k,kpt_pair in enumerate(j3mo):
for iaux,dfbasfunc in enumerate(kpt_pair):
for i,i0 in enumerate(dfbasfunc):
for j,v in enumerate(i0):
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (i+1,j+1,iaux+1,k+1,v.real,v.imag))
df_mo_tmp[i,j,iaux,k]=v
qph5.create_dataset('mo_two_e_ints/df_mo_integrals_real',data=df_mo_tmp.real)
qph5.create_dataset('mo_two_e_ints/df_mo_integrals_imag',data=df_mo_tmp.imag)
# eri_4d_ao = np.zeros((Nk,nao,Nk,nao,Nk,nao,Nk,nao), dtype=np.complex)
# for d, kd in enumerate(kpts):
# for c, kc in enumerate(kpts):
# if c > d: break
# idx2_cd = idx2_tri(c,d)
# for b, kb in enumerate(kpts):
# if b > d: break
# a = kconserv[b,c,d]
# if idx2_tri(a,b) > idx2_cd: continue
# if ((c==d) and (a>b)): continue
# ka = kpts[a]
# v = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
# v *= 1./Nk
# eri_4d_ao[a,:,b,:,c,:,d] = v
#
# eri_4d_ao = eri_4d_ao.reshape([Nk*nao]*4)
with open('W.qp','w') as outfile:
pass
for d, kd in enumerate(kpts):
for c, kc in enumerate(kpts):
if c > d: break
idx2_cd = idx2_tri((c,d))
for b, kb in enumerate(kpts):
if b > d: break
a = kconserv[b,c,d]
#if idx2_tri((a,b)) > idx2_cd: continue
if a>d: continue
#if ((c==d) and (a>b)): continue
ka = kpts[a]
with open('W.qp','a') as outfile:
eri_4d_ao_kpt = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
eri_4d_ao_kpt *= 1./Nk
for l in range(nao):
ll=l+d*nao
for j in range(nao):
jj=j+c*nao
if jj>ll: break
idx2_jjll = idx2_tri((jj,ll))
for k in range(nao):
kk=k+b*nao
if kk>ll: break
for i in range(nao):
ii=i+a*nao
if idx2_tri((ii,kk)) > idx2_jjll: break
if ((jj==ll) and (ii>kk)): break
v=eri_4d_ao_kpt[i,k,j,l]
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (ii+1,jj+1,kk+1,ll+1,v.real,v.imag))
def pyscf2QP2(cell,mf, kpts, kmesh=None, cas_idx=None, int_threshold = 1E-8,
print_ao_ints_bi=False,
print_mo_ints_bi=False,
print_ao_ints_df=True,
print_mo_ints_df=False,
print_ao_ints_mono=True,
print_mo_ints_mono=False):
'''
kpts = List of kpoints coordinates. Cannot be null, for gamma is other script
kmesh = Mesh of kpoints (optional)
cas_idx = List of active MOs. If not specified all MOs are actives
int_threshold = The integral will be not printed in they are bellow that
'''
from pyscf.pbc import ao2mo
from pyscf.pbc import tools
from pyscf.pbc.gto import ecp
from pyscf.data import nist
import h5py
import scipy
qph5=h5py.File('qpdat.h5')
qph5.create_group('nuclei')
qph5.create_group('electrons')
qph5.create_group('ao_basis')
qph5.create_group('mo_basis')
mo_coef_threshold = int_threshold
ovlp_threshold = int_threshold
kin_threshold = int_threshold
ne_threshold = int_threshold
bielec_int_threshold = int_threshold
natom = cell.natm
nelec = cell.nelectron
neleca,nelecb = cell.nelec
atom_xyz = mf.cell.atom_coords()
if not(mf.cell.unit.startswith(('B','b','au','AU'))):
atom_xyz /= nist.BOHR # always convert to au
strtype=h5py.special_dtype(vlen=str)
atom_dset=qph5.create_dataset('nuclei/nucl_label',(natom,),dtype=strtype)
for i in range(natom):
atom_dset[i] = mf.cell.atom_pure_symbol(i)
qph5.create_dataset('nuclei/nucl_coord',data=atom_xyz)
qph5.create_dataset('nuclei/nucl_charge',data=mf.cell.atom_charges())
print('n_atom per kpt', natom)
print('num_elec per kpt', nelec)
mo_coeff = mf.mo_coeff
# Mo_coeff actif
mo_k = np.array([c[:,cas_idx] for c in mo_coeff] if cas_idx is not None else mo_coeff)
e_k = np.array([e[cas_idx] for e in mf.mo_energy] if cas_idx is not None else mf.mo_energy)
Nk, nao, nmo = mo_k.shape
print("n Kpts", Nk)
print("n active Mos per kpt", nmo)
print("n AOs per kpt", nao)
naux = mf.with_df.auxcell.nao
print("n df fitting functions", naux)
#in old version: param << nelec*Nk, nmo*Nk, natom*Nk
qph5['electrons'].attrs['elec_alpha_num']=neleca*Nk
qph5['electrons'].attrs['elec_beta_num']=nelecb*Nk
qph5['mo_basis'].attrs['mo_num']=Nk*nmo
qph5['ao_basis'].attrs['ao_num']=Nk*nao
qph5['nuclei'].attrs['nucl_num']=Nk*natom
qph5['nuclei'].attrs['kpt_num']=Nk
qph5.create_group('ao_two_e_ints')
qph5['ao_two_e_ints'].attrs['df_num']=naux
qph5['ao_basis'].attrs['ao_basis']=mf.cell.basis
ao_nucl=[mf.cell.bas_atom(i)+1 for i in range(nao)]
qph5.create_dataset('ao_basis/ao_nucl',data=Nk*ao_nucl)
# _
# |\ | _ | _ _. ._ |_) _ ._ | _ o _ ._
# | \| |_| (_ | (/_ (_| | | \ (/_ |_) |_| | _> | (_) | |
# |
#Total energy shift due to Ewald probe charge = -1/2 * Nelec*madelung/cell.vol =
shift = tools.pbc.madelung(cell, kpts)*cell.nelectron * -.5
e_nuc = (cell.energy_nuc() + shift)*Nk
print('nucl_repul', e_nuc)
qph5['nuclei'].attrs['nuclear_repulsion']=e_nuc
# __ __ _
# |\/| | | | _ _ |_ _
# | | |__| |__ (_) (/_ | _>
#
mo_coef_blocked=scipy.linalg.block_diag(*mo_k)
qph5.create_dataset('mo_basis/mo_coef_real',data=mo_coef_blocked.real)
qph5.create_dataset('mo_basis/mo_coef_imag',data=mo_coef_blocked.imag)
qph5.create_dataset('mo_basis/mo_coef_kpts_real',data=mo_k.real)
qph5.create_dataset('mo_basis/mo_coef_kpts_imag',data=mo_k.imag)
with open('C.qp','w') as outfile:
c_kpts = np.reshape(mo_k,(Nk,nao,nmo))
for ik in range(Nk):
shift1=ik*nao+1
shift2=ik*nmo+1
for i in range(nao):
for j in range(nmo):
cij = c_kpts[ik,i,j]
if abs(cij) > mo_coef_threshold:
outfile.write('%s %s %s %s\n' % (i+shift1, j+shift2, cij.real, cij.imag))
# ___
# | ._ _|_ _ _ ._ _. | _ |\/| _ ._ _
# _|_ | | |_ (/_ (_| | (_| | _> | | (_) | | (_)
# _|
if mf.cell.pseudo:
v_kpts_ao = np.reshape(mf.with_df.get_pp(kpts=kpts),(Nk,nao,nao))
else:
v_kpts_ao = np.reshape(mf.with_df.get_nuc(kpts=kpts),(Nk,nao,nao))
if len(cell._ecpbas) > 0:
v_kpts_ao += np.reshape(ecp.ecp_int(cell, kpts),(Nk,nao,nao))
ne_ao = ('V',v_kpts_ao,ne_threshold)
ovlp_ao = ('S',np.reshape(mf.get_ovlp(cell=cell,kpts=kpts),(Nk,nao,nao)),ovlp_threshold)
kin_ao = ('T',np.reshape(cell.pbc_intor('int1e_kin',1,1,kpts=kpts),(Nk,nao,nao)),kin_threshold)
kin_ao_blocked=scipy.linalg.block_diag(*kin_ao[1])
ovlp_ao_blocked=scipy.linalg.block_diag(*ovlp_ao[1])
ne_ao_blocked=scipy.linalg.block_diag(*v_kpts_ao)
qph5.create_dataset('ao_one_e_ints/ao_integrals_kinetic_real',data=kin_ao_blocked.real)
qph5.create_dataset('ao_one_e_ints/ao_integrals_kinetic_imag',data=kin_ao_blocked.imag)
qph5.create_dataset('ao_one_e_ints/ao_integrals_overlap_real',data=ovlp_ao_blocked.real)
qph5.create_dataset('ao_one_e_ints/ao_integrals_overlap_imag',data=ovlp_ao_blocked.imag)
qph5.create_dataset('ao_one_e_ints/ao_integrals_n_e_real', data=ne_ao_blocked.real)
qph5.create_dataset('ao_one_e_ints/ao_integrals_n_e_imag', data=ne_ao_blocked.imag)
for name, intval_kpts_ao, thresh in (ne_ao, ovlp_ao, kin_ao):
if print_ao_ints_mono:
with open('%s.qp' % name,'w') as outfile:
for ik in range(Nk):
shift=ik*nao+1
for i in range(nao):
for j in range(i,nao):
int_ij = intval_kpts_ao[ik,i,j]
if abs(int_ij) > thresh:
outfile.write('%s %s %s %s\n' % (i+shift, j+shift, int_ij.real, int_ij.imag))
if print_mo_ints_mono:
intval_kpts_mo = np.einsum('kim,kij,kjn->kmn',mo_k.conj(),intval_kpts_ao,mo_k)
with open('%s_mo.qp' % name,'w') as outfile:
for ik in range(Nk):
shift=ik*nmo+1
for i in range(nmo):
for j in range(i,nmo):
int_ij = intval_kpts_mo[ik,i,j]
if abs(int_ij) > thresh:
outfile.write('%s %s %s %s\n' % (i+shift, j+shift, int_ij.real, int_ij.imag))
# ___ _
# | ._ _|_ _ _ ._ _. | _ |_) o
# _|_ | | |_ (/_ (_| | (_| | _> |_) |
# _|
#
kconserv = tools.get_kconserv(cell, kpts)
qph5.create_dataset('nuclei/kconserv',data=np.transpose(kconserv+1,(0,2,1)))
kcon_test = np.zeros((Nk,Nk,Nk),dtype=int)
for a in range(Nk):
for b in range(Nk):
for c in range(Nk):
kcon_test[a,c,b] = kconserv[a,b,c]+1
qph5.create_dataset('nuclei/kconserv_test',data=kcon_test)
with open('K.qp','w') as outfile:
for a in range(Nk):
for b in range(Nk):
for c in range(Nk):
d = kconserv[a,b,c]
outfile.write('%s %s %s %s\n' % (a+1,c+1,b+1,d+1))
intfile=h5py.File(mf.with_df._cderi,'r')
j3c = intfile.get('j3c')
naosq = nao*nao
naotri = (nao*(nao+1))//2
j3ckeys = list(j3c.keys())
j3ckeys.sort(key=lambda strkey:int(strkey))
# in new(?) version of PySCF, there is an extra layer of groups before the datasets
# datasets used to be [/j3c/0, /j3c/1, /j3c/2, ...]
# datasets now are [/j3c/0/0, /j3c/1/0, /j3c/2/0, ...]
j3clist = [j3c.get(i+'/0') for i in j3ckeys]
if j3clist==[None]*len(j3clist):
# if using older version, stop before last level
j3clist = [j3c.get(i) for i in j3ckeys]
nkinvsq = 1./np.sqrt(Nk)
# dimensions are (kikj,iaux,jao,kao), where kikj is compound index of kpts i and j
# output dimensions should be reversed (nao, nao, naux, nkptpairs)
j3arr=np.array([(i.value.reshape([-1,nao,nao]) if (i.shape[1] == naosq) else makesq3(i.value,nao)) * nkinvsq for i in j3clist])
nkpt_pairs = j3arr.shape[0]
df_ao_tmp = np.zeros((nao,nao,naux,nkpt_pairs),dtype=np.complex128)
if print_ao_ints_df:
with open('D.qp','w') as outfile:
pass
with open('D.qp','a') as outfile:
for k,kpt_pair in enumerate(j3arr):
for iaux,dfbasfunc in enumerate(kpt_pair):
for i,i0 in enumerate(dfbasfunc):
for j,v in enumerate(i0):
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (i+1,j+1,iaux+1,k+1,v.real,v.imag))
df_ao_tmp[i,j,iaux,k]=v
qph5.create_dataset('ao_two_e_ints/df_ao_integrals_real',data=df_ao_tmp.real)
qph5.create_dataset('ao_two_e_ints/df_ao_integrals_imag',data=df_ao_tmp.imag)
if print_mo_ints_df:
kpair_list=[]
for i in range(Nk):
for j in range(Nk):
if(i>=j):
kpair_list.append((i,j,idx2_tri((i,j))))
j3mo = np.array([np.einsum('mij,ik,jl->mkl',j3arr[kij],mo_k[ki].conj(),mo_k[kj]) for ki,kj,kij in kpair_list])
df_mo_tmp = np.zeros((nmo,nmo,naux,nkpt_pairs),dtype=np.complex128)
with open('D_mo.qp','w') as outfile:
pass
with open('D_mo.qp','a') as outfile:
for k,kpt_pair in enumerate(j3mo):
for iaux,dfbasfunc in enumerate(kpt_pair):
for i,i0 in enumerate(dfbasfunc):
for j,v in enumerate(i0):
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (i+1,j+1,iaux+1,k+1,v.real,v.imag))
df_mo_tmp[i,j,iaux,k]=v
qph5.create_dataset('mo_two_e_ints/df_mo_integrals_real',data=df_mo_tmp.real)
qph5.create_dataset('mo_two_e_ints/df_mo_integrals_imag',data=df_mo_tmp.imag)
# eri_4d_ao = np.zeros((Nk,nao,Nk,nao,Nk,nao,Nk,nao), dtype=np.complex)
# for d, kd in enumerate(kpts):
# for c, kc in enumerate(kpts):
# if c > d: break
# idx2_cd = idx2_tri(c,d)
# for b, kb in enumerate(kpts):
# if b > d: break
# a = kconserv[b,c,d]
# if idx2_tri(a,b) > idx2_cd: continue
# if ((c==d) and (a>b)): continue
# ka = kpts[a]
# v = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
# v *= 1./Nk
# eri_4d_ao[a,:,b,:,c,:,d] = v
#
# eri_4d_ao = eri_4d_ao.reshape([Nk*nao]*4)
if (print_ao_ints_bi or print_mo_ints_bi):
if print_ao_ints_bi:
with open('W.qp','w') as outfile:
pass
if print_mo_ints_bi:
with open('W_mo.qp','w') as outfile:
pass
for d, kd in enumerate(kpts):
for c, kc in enumerate(kpts):
if c > d: break
idx2_cd = idx2_tri((c,d))
for b, kb in enumerate(kpts):
if b > d: break
a = kconserv[b,c,d]
#if idx2_tri((a,b)) > idx2_cd: continue
if a > d: continue
#if ((c==d) and (a>b)): continue
ka = kpts[a]
if print_ao_ints_bi:
with open('W.qp','a') as outfile:
eri_4d_ao_kpt = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
eri_4d_ao_kpt *= 1./Nk
for l in range(nao):
ll=l+d*nao
for j in range(nao):
jj=j+c*nao
if jj>ll: break
idx2_jjll = idx2_tri((jj,ll))
for k in range(nao):
kk=k+b*nao
if kk>ll: break
for i in range(nao):
ii=i+a*nao
if idx2_tri((ii,kk)) > idx2_jjll: break
if ((jj==ll) and (ii>kk)): break
v=eri_4d_ao_kpt[i,k,j,l]
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (ii+1,jj+1,kk+1,ll+1,v.real,v.imag))
if print_mo_ints_bi:
with open('W_mo.qp','a') as outfile:
eri_4d_mo_kpt = mf.with_df.ao2mo([mo_k[a], mo_k[b], mo_k[c], mo_k[d]],
[ka,kb,kc,kd],compact=False).reshape((nmo,)*4)
eri_4d_mo_kpt *= 1./Nk
for l in range(nmo):
ll=l+d*nmo
for j in range(nmo):
jj=j+c*nmo
if jj>ll: break
idx2_jjll = idx2_tri((jj,ll))
for k in range(nmo):
kk=k+b*nmo
if kk>ll: break
for i in range(nmo):
ii=i+a*nmo
if idx2_tri((ii,kk)) > idx2_jjll: break
if ((jj==ll) and (ii>kk)): break
v=eri_4d_mo_kpt[i,k,j,l]
if (abs(v) > bielec_int_threshold):
outfile.write('%s %s %s %s %s %s\n' % (ii+1,jj+1,kk+1,ll+1,v.real,v.imag))
#def testpyscf2QP(cell,mf, kpts, kmesh=None, cas_idx=None, int_threshold = 1E-8):
# '''
# kpts = List of kpoints coordinates. Cannot be null, for gamma is other script
# kmesh = Mesh of kpoints (optional)
# cas_idx = List of active MOs. If not specified all MOs are actives
# int_threshold = The integral will be not printed in they are bellow that
# '''
#
# from pyscf.pbc import ao2mo
# from pyscf.pbc import tools
# from pyscf.pbc.gto import ecp
#
# mo_coef_threshold = int_threshold
# ovlp_threshold = int_threshold
# kin_threshold = int_threshold
# ne_threshold = int_threshold
# bielec_int_threshold = int_threshold
#
# natom = len(cell.atom_coords())
# print('n_atom per kpt', natom)
# print('num_elec per kpt', cell.nelectron)
#
# mo_coeff = mf.mo_coeff
# # Mo_coeff actif
# mo_k = np.array([c[:,cas_idx] for c in mo_coeff] if cas_idx is not None else mo_coeff)
# e_k = np.array([e[cas_idx] for e in mf.mo_energy] if cas_idx is not None else mf.mo_energy)
#
# Nk, nao, nmo = mo_k.shape
# print("n Kpts", Nk)
# print("n active Mos per kpt", nmo)
# print("n AOs per kpt", nao)
#
# naux = mf.with_df.get_naoaux()
# print("n df fitting functions", naux)
#
# # _
# # |\ | _ | _ _. ._ |_) _ ._ | _ o _ ._
# # | \| |_| (_ | (/_ (_| | | \ (/_ |_) |_| | _> | (_) | |
# # |
#
# #Total energy shift due to Ewald probe charge = -1/2 * Nelec*madelung/cell.vol =
# shift = tools.pbc.madelung(cell, kpts)*cell.nelectron * -.5
# e_nuc = (cell.energy_nuc() + shift)*Nk
#
# print('nucl_repul', e_nuc)
#
#
# # ___
# # | ._ _|_ _ _ ._ _. | _ |\/| _ ._ _
# # _|_ | | |_ (/_ (_| | (_| | _> | | (_) | | (_)
# # _|
#
# if mf.cell.pseudo:
# v_kpts_ao = np.reshape(mf.with_df.get_pp(kpts=kpts),(Nk,nao,nao))
# else:
# v_kpts_ao = np.reshape(mf.with_df.get_nuc(kpts=kpts),(Nk,nao,nao))
# if len(cell._ecpbas) > 0:
# v_kpts_ao += np.reshape(ecp.ecp_int(cell, kpts),(Nk,nao,nao))
#
# ne_ao = ('ne',v_kpts_ao,ne_threshold)
# ovlp_ao = ('overlap',np.reshape(mf.get_ovlp(cell=cell,kpts=kpts),(Nk,nao,nao)),ovlp_threshold)
# kin_ao = ('kinetic',np.reshape(cell.pbc_intor('int1e_kin',1,1,kpts=kpts),(Nk,nao,nao)),kin_threshold)
#
#
# # ___ _
# # | ._ _|_ _ _ ._ _. | _ |_) o
# # _|_ | | |_ (/_ (_| | (_| | _> |_) |
# # _|
# #
# kconserv = tools.get_kconserv(cell, kpts)
#
#
# import h5py
#
# intfile=h5py.File(mf.with_df._cderi,'r')
#
# j3c = intfile.get('j3c')
# naosq = nao*nao
# naotri = (nao*(nao+1))//2
# j3keys = list(j3c.keys())
# j3keys.sort(key=lambda x:int(x))
# j3clist = [j3c.get(i) for i in j3keys]
# nkinvsq = 1./np.sqrt(Nk)
#
# # dimensions are (kikj,iaux,jao,kao), where kikj is compound index of kpts i and j
# # output dimensions should be reversed (nao, nao, naux, nkptpairs)
# j3arr=np.array([(pad(i.value.reshape([-1,nao,nao]),[naux,nao,nao]) if (i.shape[1] == naosq) else makesq(i.value,naux,nao)) * nkinvsq for i in j3clist])
#
# nkpt_pairs = j3arr.shape[0]
#
# kpair_list=[]
# for i in range(Nk):
# for j in range(Nk):
# if(i>=j):
# kpair_list.append((i,j,idx2_tri((i,j))))
# j3mo = np.array([np.einsum('mij,ik,jl->mkl',j3arr[kij,:,:,:],mo_k[ki,:,:].conj(),mo_k[kj,:,:]) for ki,kj,kij in kpair_list])
#
#
#
# eri_mo = np.zeros(4*[nmo*Nk],dtype=np.complex128)
# eri_ao = np.zeros(4*[nao*Nk],dtype=np.complex128)
#
# for d, kd in enumerate(kpts):
# for c, kc in enumerate(kpts):
# for b, kb in enumerate(kpts):
# a = kconserv[b,c,d]
# ka = kpts[a]
# eri_4d_ao_kpt = mf.with_df.get_ao_eri(kpts=[ka,kb,kc,kd],compact=False).reshape((nao,)*4)
# eri_4d_ao_kpt *= 1./Nk
# for l in range(nao):
# ll=l+d*nao
# for j in range(nao):
# jj=j+c*nao
# for k in range(nao):
# kk=k+b*nao
# for i in range(nao):
# ii=i+a*nao
# v=eri_4d_ao_kpt[i,k,j,l]
# eri_ao[ii,kk,jj,ll]=v
#
# eri_4d_mo_kpt = mf.with_df.ao2mo([mo_k[a], mo_k[b], mo_k[c], mo_k[d]],
# [ka,kb,kc,kd],compact=False).reshape((nmo,)*4)
# eri_4d_mo_kpt *= 1./Nk
# for l in range(nmo):
# ll=l+d*nmo
# for j in range(nmo):
# jj=j+c*nmo
# for k in range(nmo):
# kk=k+b*nmo
# for i in range(nmo):
# ii=i+a*nmo
# v=eri_4d_mo_kpt[i,k,j,l]
# eri_mo[ii,kk,jj,ll]=v
#
# return (mo_k,j3arr,j3mo,eri_ao,eri_mo,kpair_list)