def set_log(self, log=None): """Set output log.""" if log is None: self.timer = nulltimer elif log == '-': self.timer = StepTimer(name='elph') else: self.timer = StepTimer(name='elph', out=open(log, 'w'))
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