def rotate_matrix(self, A_o, A_MM): assert A_o.ndim == 1 A_ww = dots(self.U_ow.T.conj() * A_o, self.V_oM, self.U_Mw) A_ww += np.conj(A_ww.T) A_ww += np.dot(self.U_ow.T.conj() * A_o, self.U_ow) A_ww += dots(self.U_Mw.T.conj(), A_MM, self.U_Mw) return A_ww
def get_lcao_xc(calc, P_aqMi, bfs=None, spin=0): nq = len(calc.wfs.ibzk_qc) nao = calc.wfs.setups.nao dtype = calc.wfs.dtype if bfs is None: bfs = get_bfs(calc) if calc.density.nt_sg is None: calc.density.interpolate() nt_sg = calc.density.nt_sg vxct_sg = calc.density.finegd.zeros(calc.wfs.nspins) calc.hamiltonian.xc.calculate(calc.density.finegd, nt_sg, vxct_sg) vxct_G = calc.wfs.gd.zeros() calc.hamiltonian.restrict(vxct_sg[spin], vxct_G) Vxc_qMM = np.zeros((nq, nao, nao), dtype) for q, Vxc_MM in enumerate(Vxc_qMM): bfs.calculate_potential_matrix(vxct_G, Vxc_MM, q) tri2full(Vxc_MM, "L") # Add atomic PAW corrections for a, P_qMi in P_aqMi.items(): D_sp = calc.density.D_asp[a][:] H_sp = np.zeros_like(D_sp) calc.wfs.setups[a].xc_correction.calculate(calc.hamiltonian.xc, D_sp, H_sp) H_ii = unpack(H_sp[spin]) for Vxc_MM, P_Mi in zip(Vxc_qMM, P_qMi): Vxc_MM += dots(P_Mi, H_ii, P_Mi.T.conj()) return Vxc_qMM * Hartree
def get_Fcore(self, q=0, indices=None): if indices is None: Fcore_ww = np.zeros_like(self.H_qww[q]) else: Fcore_ww = np.zeros((len(indices), len(indices))) for a, P_wi in self.get_projections(q, indices).items(): X_ii = unpack(self.calc.wfs.setups[a].X_p) Fcore_ww -= dots(P_wi, X_ii, P_wi.T.conj()) return Fcore_ww * Hartree
def get_rot(F_MM, V_oM, L): eps_M, U_MM = np.linalg.eigh(F_MM) indices = eps_M.real.argsort()[-L:] U_Ml = U_MM[:, indices] U_Ml /= np.sqrt(dots(U_Ml.T.conj(), F_MM, U_Ml).diagonal()) U_ow = V_oM.copy() U_lw = np.dot(U_Ml.T.conj(), F_MM) for col1, col2 in zip(U_ow.T, U_lw.T): norm = np.linalg.norm(np.hstack((col1, col2))) col1 /= norm col2 /= norm return U_ow, U_lw, U_Ml
def __init__(self, V_nM, No, ortho=False): Nw = V_nM.shape[1] assert No <= Nw V_oM, V_uM = V_nM[:No], V_nM[No:] F_MM = np.dot(V_uM.T.conj(), V_uM) U_ow, U_lw, U_Ml = get_rot(F_MM, V_oM, Nw - No) self.U_nw = np.vstack((U_ow, dots(V_uM, U_Ml, U_lw))) # stop here ?? XXX self.S_ww = self.rotate_matrix(np.ones(1)) if ortho: lowdin(self.U_nw, self.S_ww) self.S_ww = np.identity(Nw) self.norms_n = np.dot(self.U_nw, np.linalg.solve(self.S_ww, self.U_nw.T.conj())).diagonal()
def __init__(self, V_nM, No, ortho=False): Nw = V_nM.shape[1] assert No <= Nw V_oM, V_uM = V_nM[:No], V_nM[No:] F_MM = np.dot(V_uM.T.conj(), V_uM) U_ow, U_lw, U_Ml = get_rot(F_MM, V_oM, Nw - No) self.U_nw = np.vstack((U_ow, dots(V_uM, U_Ml, U_lw))) # stop here ?? XXX self.S_ww = self.rotate_matrix(np.ones(1)) if ortho: lowdin(self.U_nw, self.S_ww) self.S_ww = np.identity(Nw) self.norms_n = np.dot(self.U_nw, np.linalg.solve( self.S_ww, self.U_nw.T.conj())).diagonal()
def get_xc2(calc, w_wG, P_awi, spin=0): if calc.density.nt_sg is None: calc.density.interpolate() nt_g = calc.density.nt_sg[spin] vxct_g = calc.density.finegd.zeros() calc.hamiltonian.xc.get_energy_and_potential(nt_g, vxct_g) vxct_G = calc.wfs.gd.empty() calc.hamiltonian.restrict(vxct_g, vxct_G) # Integrate pseudo part Nw = len(w_wG) xc_ww = np.empty((Nw, Nw)) r2k(0.5 * calc.wfs.gd.dv, w_wG, vxct_G * w_wG, 0.0, xc_ww) tri2full(xc_ww, "L") # Add atomic PAW corrections for a, P_wi in P_awi.items(): D_sp = calc.density.D_asp[a][:] H_sp = np.zeros_like(D_sp) calc.wfs.setups[a].xc_correction.calculate_energy_and_derivatives(D_sp, H_sp) H_ii = unpack(H_sp[spin]) xc_ww += dots(P_wi, H_ii, P_wi.T.conj()) return xc_ww * Hartree
def get_xc2(calc, w_wG, P_awi, spin=0): if calc.density.nt_sg is None: calc.density.interpolate_pseudo_density() nt_g = calc.density.nt_sg[spin] vxct_g = calc.density.finegd.zeros() calc.hamiltonian.xc.get_energy_and_potential(nt_g, vxct_g) vxct_G = calc.wfs.gd.empty() calc.hamiltonian.restrict_and_collect(vxct_g, vxct_G) # Integrate pseudo part Nw = len(w_wG) xc_ww = np.empty((Nw, Nw)) r2k(.5 * calc.wfs.gd.dv, w_wG, vxct_G * w_wG, .0, xc_ww) tri2full(xc_ww, 'L') # Add atomic PAW corrections for a, P_wi in P_awi.items(): D_sp = calc.density.D_asp[a][:] H_sp = np.zeros_like(D_sp) calc.wfs.setups[a].xc_correction.calculate_energy_and_derivatives( D_sp, H_sp) H_ii = unpack(H_sp[spin]) xc_ww += dots(P_wi, H_ii, P_wi.T.conj()) return xc_ww * Hartree
def rotate_matrix(self, A_nn): if A_nn.ndim == 1: return np.dot(self.U_nw.T.conj() * A_nn, self.U_nw) else: return dots(self.U_nw.T.conj(), A_nn, self.U_nw)
def get_M(self, modes, log=None, q=0): """Calculate el-ph coupling matrix for given modes(s). XXX: kwarg "q=0" is an ugly hack for k-points. There shuold be loops over q! Note that modes must be given as a dictionary with mode frequencies in eV and corresponding mode vectors in units of 1/sqrt(amu), where amu = 1.6605402e-27 Kg is an atomic mass unit. In short frequencies and mode vectors must be given in ase units. :: d d ~ < w | -- v | w' > = < w | -- v | w'> dP dP _ \ ~a d . ~a + ) < w | p > -- /_\H < p | w' > /_ i dP ij j a,ij _ \ d ~a . ~a + ) < w | -- p > /_\H < p | w' > /_ dP i ij j a,ij _ \ ~a . d ~a + ) < w | p > /_\H < -- p | w' > /_ i ij dP j a,ij """ if log is None: timer = nulltimer elif log == '-': timer = StepTimer(name='EPCM') else: timer = StepTimer(name='EPCM', out=open(log, 'w')) modes1 = modes.copy() #convert to atomic units amu = 1.6605402e-27 # atomic unit mass [Kg] me = 9.1093897e-31 # electron mass [Kg] modes = {} for k in modes1.keys(): modes[k / Hartree] = modes1[k] / np.sqrt(amu / me) dvt_Gx, ddH_aspx = self.get_gradient() from gpaw import restart atoms, calc = restart('eq.gpw', txt=None) if calc.wfs.S_qMM is None: calc.initialize(atoms) calc.initialize_positions(atoms) wfs = calc.wfs nao = wfs.setups.nao bfs = wfs.basis_functions dtype = wfs.dtype spin = 0 # XXX M_lii = {} timer.write_now('Starting gradient of pseudo part') for f, mode in modes.items(): mo = [] M_ii = np.zeros((nao, nao), dtype) for a in self.indices: mo.append(mode[a]) mode = np.asarray(mo).flatten() dvtdP_G = np.dot(dvt_Gx, mode) bfs.calculate_potential_matrix(dvtdP_G, M_ii, q=q) tri2full(M_ii, 'L') M_lii[f] = M_ii timer.write_now('Finished gradient of pseudo part') P_aqMi = calc.wfs.P_aqMi # Add the term # _ # \ ~a d . ~a # ) < w | p > -- /_\H < p | w' > # /_ i dP ij j # a,ij Ma_lii = {} for f, mode in modes.items(): Ma_lii[f] = np.zeros_like(M_lii.values()[0]) timer.write_now('Starting gradient of dH^a part') for f, mode in modes.items(): mo = [] for a in self.indices: mo.append(mode[a]) mode = np.asarray(mo).flatten() for a, ddH_spx in ddH_aspx.items(): ddHdP_sp = np.dot(ddH_spx, mode) ddHdP_ii = unpack2(ddHdP_sp[spin]) Ma_lii[f] += dots(P_aqMi[a][q], ddHdP_ii, P_aqMi[a][q].T) timer.write_now('Finished gradient of dH^a part') timer.write_now('Starting gradient of projectors part') dP_aMix = self.get_dP_aMix(calc.spos_ac, wfs, q, timer) timer.write_now('Finished gradient of projectors part') dH_asp = pickle.load(open('v.eq.pckl', 'rb'))[1] Mb_lii = {} for f, mode in modes.items(): Mb_lii[f] = np.zeros_like(M_lii.values()[0]) for f, mode in modes.items(): for a, dP_Mix in dP_aMix.items(): dPdP_Mi = np.dot(dP_Mix, mode[a]) dH_ii = unpack2(dH_asp[a][spin]) dPdP_MM = dots(dPdP_Mi, dH_ii, P_aqMi[a][q].T) Mb_lii[f] -= dPdP_MM + dPdP_MM.T # XXX The minus sign here is quite subtle. # It is related to how the derivative of projector # functions in GPAW is calculated. # More thorough explanations, anyone...? # Units of M_lii are Hartree/(Bohr * sqrt(m_e)) for mode in M_lii.keys(): M_lii[mode] += Ma_lii[mode] + Mb_lii[mode] # conversion to eV. The prefactor 1 / sqrt(hb^2 / 2 * hb * f) # has units Bohr * sqrt(me) M_lii_1 = M_lii.copy() M_lii = {} for f in M_lii_1.keys(): M_lii[f * Hartree] = M_lii_1[f] * Hartree / np.sqrt(2 * f) return M_lii
def get_M(self, modes, log=None, q=0): """Calculate el-ph coupling matrix for given modes(s). XXX: kwarg "q=0" is an ugly hack for k-points. There shuold be loops over q! Note that modes must be given as a dictionary with mode frequencies in eV and corresponding mode vectors in units of 1/sqrt(amu), where amu = 1.6605402e-27 Kg is an atomic mass unit. In short frequencies and mode vectors must be given in ase units. :: d d ~ < w | -- v | w' > = < w | -- v | w'> dP dP _ \ ~a d . ~a + ) < w | p > -- /_\H < p | w' > /_ i dP ij j a,ij _ \ d ~a . ~a + ) < w | -- p > /_\H < p | w' > /_ dP i ij j a,ij _ \ ~a . d ~a + ) < w | p > /_\H < -- p | w' > /_ i ij dP j a,ij """ if log is None: timer = nulltimer elif log == '-': timer = StepTimer(name='EPCM') else: timer = StepTimer(name='EPCM', out=open(log, 'w')) modes1 = modes.copy() #convert to atomic units amu = 1.6605402e-27 # atomic unit mass [Kg] me = 9.1093897e-31 # electron mass [Kg] modes = {} for k in modes1.keys(): modes[k / Hartree] = modes1[k] / np.sqrt(amu / me) dvt_Gx, ddH_aspx = self.get_gradient() from gpaw import restart atoms, calc = restart('eq.gpw', txt=None) spos_ac = atoms.get_scaled_positions() if calc.wfs.S_qMM is None: calc.initialize(atoms) calc.initialize_positions(atoms) wfs = calc.wfs nao = wfs.setups.nao bfs = wfs.basis_functions dtype = wfs.dtype spin = 0 # XXX M_lii = {} timer.write_now('Starting gradient of pseudo part') for f, mode in modes.items(): mo = [] M_ii = np.zeros((nao, nao), dtype) for a in self.indices: mo.append(mode[a]) mode = np.asarray(mo).flatten() dvtdP_G = np.dot(dvt_Gx, mode) bfs.calculate_potential_matrix(dvtdP_G, M_ii, q=q) tri2full(M_ii, 'L') M_lii[f] = M_ii timer.write_now('Finished gradient of pseudo part') P_aqMi = calc.wfs.P_aqMi # Add the term # _ # \ ~a d . ~a # ) < w | p > -- /_\H < p | w' > # /_ i dP ij j # a,ij Ma_lii = {} for f, mode in modes.items(): Ma_lii[f] = np.zeros_like(M_lii.values()[0]) timer.write_now('Starting gradient of dH^a part') for f, mode in modes.items(): mo = [] for a in self.indices: mo.append(mode[a]) mode = np.asarray(mo).flatten() for a, ddH_spx in ddH_aspx.items(): ddHdP_sp = np.dot(ddH_spx, mode) ddHdP_ii = unpack2(ddHdP_sp[spin]) Ma_lii[f] += dots(P_aqMi[a][q], ddHdP_ii, P_aqMi[a][q].T) timer.write_now('Finished gradient of dH^a part') timer.write_now('Starting gradient of projectors part') spos_ac = self.atoms.get_scaled_positions() % 1.0 dP_aMix = self.get_dP_aMix(spos_ac, wfs, q, timer) timer.write_now('Finished gradient of projectors part') dH_asp = pickle.load(open('v.eq.pckl'))[1] Mb_lii = {} for f, mode in modes.items(): Mb_lii[f] = np.zeros_like(M_lii.values()[0]) for f, mode in modes.items(): for a, dP_Mix in dP_aMix.items(): dPdP_Mi = np.dot(dP_Mix, mode[a]) dH_ii = unpack2(dH_asp[a][spin]) dPdP_MM = dots(dPdP_Mi, dH_ii, P_aqMi[a][q].T) Mb_lii[f] -= dPdP_MM + dPdP_MM.T # XXX The minus sign here is quite subtle. # It is related to how the derivative of projector # functions in GPAW is calculated. # More thorough explanations, anyone...? # Units of M_lii are Hartree/(Bohr * sqrt(m_e)) for mode in M_lii.keys(): M_lii[mode] += Ma_lii[mode] + Mb_lii[mode] # conversion to eV. The prefactor 1 / sqrt(hb^2 / 2 * hb * f) # has units Bohr * sqrt(me) M_lii_1 = M_lii.copy() M_lii = {} for f in M_lii_1.keys(): M_lii[f * Hartree] = M_lii_1[f] * Hartree / np.sqrt(2 * f) return M_lii