def get_effective_volume_ratio(self, atom_index): """Effective volume to free volume ratio. After: Tkatchenko and Scheffler PRL 102 (2009) 073005, eq. (7) """ atoms = self.atoms finegd = self.calculator.density.finegd den_sg, gd = self.calculator.density.get_all_electron_density(atoms) den_g = den_sg.sum(axis=0) assert (gd == finegd) denfree_g, gd = self.hdensity.get_density([atom_index]) assert (gd == finegd) # the atoms r^3 grid position = self.atoms[atom_index].position / Bohr r_vg, r2_g = coordinates(finegd, origin=position) r3_g = r2_g * np.sqrt(r2_g) weight_g = denfree_g * self.invweight_g nom = finegd.integrate(r3_g * den_g * weight_g) denom = finegd.integrate(r3_g * denfree_g) return nom / denom
def get_effective_volume_ratio(self, atom_index): """Effective volume to free volume ratio. After: Tkatchenko and Scheffler PRL 102 (2009) 073005, eq. (7) """ atoms = self.atoms finegd = self.calculator.density.finegd den_sg, gd = self.calculator.density.get_all_electron_density(atoms) den_g = den_sg.sum(axis=0) assert gd == finegd denfree_g, gd = self.hdensity.get_density([atom_index]) assert gd == finegd # the atoms r^3 grid position = self.atoms[atom_index].position / Bohr r_vg, r2_g = coordinates(finegd, origin=position) r3_g = r2_g * np.sqrt(r2_g) weight_g = denfree_g * self.invweight_g nom = finegd.integrate(r3_g * den_g * weight_g) denom = finegd.integrate(r3_g * denfree_g) return nom / denom
def __init__(self, gd, a=19., center=None): self.gd = gd self.xyz, self.r2 = coordinates(gd, center) self.r = np.sqrt(self.r2) self.set_width(a) self.exp_ar2 = exp(-self.a * self.r2) self.erf_sar = erf(sqrt(self.a) * self.r)
def wignerseitz(gd, atoms, scale=None): """Determine which atom is closest to each grid point. The atom distances might be scaled by the scale list.""" if scale is None: scale = [1.] * len(atoms) else: assert(len(scale) == len(atoms)) r_vG, R2min_G = coordinates(gd, atoms[0].position / Bohr) R2min_G *= scale[0]**2 index_G = gd.zeros(dtype=int) for a, atom in enumerate(atoms[1:]): r_vG, r2_G = coordinates(gd, atom.position / Bohr) r2_G *= scale[a + 1]**2 index_G = np.where(R2min_G > r2_G, a + 1, index_G) R2min_G = np.where(R2min_G > r2_G, r2_G, R2min_G) return index_G
def initialize(self): """Initialize grids.""" center = self.center Rmax = self.Rmax dR = self.dR gd = self.gd # initialize the ylm and Radial grids # self.V_R will contain the volume of the R shell # self.R_g will contain the radial indicees corresponding to # each grid point # self.ball_g will contain the mask of the ball of radius Rmax # self.y_Lg will contain the YL values corresponding to # each grid point V_R = np.empty((int(Rmax / dR + 1),)) R_R = np.empty((int(Rmax / dR + 1),)) r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78) r_g = np.sqrt(r2_g) rhat_cg = r_cg / r_g ball_g = np.where(r_g < Rmax, 1, 0) self.R_g = np.where(r_g < Rmax, r_g / dR, -1).astype(int) if hasattr(self, 'L_l'): # ExpandYl npY = np.vectorize(Y, (float,), 'spherical harmonic') nL = len(self.L_l) y_Lg = [] for L in range(nL): y_Lg.append(npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2])) self.y_Lg = y_Lg for i, v in enumerate(V_R): R_g = np.where(self.R_g == i, 1., 0.) V_R[i] = gd.integrate(R_g) R_R[i] = gd.integrate(R_g * r_g) self.ball_g = ball_g self.V_R = V_R self.nominalR_R = self.dR * (np.arange(len(self.V_R)) + .5) V_R = np.where(V_R > 0, V_R, -1) self.R_R = np.where(V_R > 0, R_R / V_R, self.nominalR_R)
def initialize(self): """Initialize grids.""" center = self.center Rmax = self.Rmax dR = self.dR gd = self.gd # initialize the ylm and Radial grids # self.V_R will contain the volume of the R shell # self.R_g will contain the radial indicees corresponding to # each grid point # self.ball_g will contain the mask of the ball of radius Rmax # self.y_Lg will contain the YL values corresponding to # each grid point V_R = np.empty((int(Rmax / dR + 1), )) R_R = np.empty((int(Rmax / dR + 1), )) r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78) r_g = np.sqrt(r2_g) rhat_cg = r_cg / r_g ball_g = np.where(r_g < Rmax, 1, 0) self.R_g = np.where(r_g < Rmax, r_g / dR, -1).astype(int) if hasattr(self, 'L_l'): # ExpandYl npY = np.vectorize(Y, (float, ), 'spherical harmonic') nL = len(self.L_l) y_Lg = [] for L in range(nL): y_Lg.append(npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2])) self.y_Lg = y_Lg for i, v in enumerate(V_R): R_g = np.where(self.R_g == i, 1., 0.) V_R[i] = gd.integrate(R_g) R_R[i] = gd.integrate(R_g * r_g) self.ball_g = ball_g self.V_R = V_R self.nominalR_R = self.dR * (np.arange(len(self.V_R)) + .5) V_R = np.where(V_R > 0, V_R, -1) self.R_R = np.where(V_R > 0, R_R / V_R, self.nominalR_R)
def initialize(self, gd): """Initialize Y_L arrays""" self.gd = gd r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78) r_g = np.sqrt(r2_g) rhat_cg = r_cg / r_g self.l_L = [] self.y_Lg = [] npY = np.vectorize(Y, (float, ), 'spherical harmonic') L = 0 for l in range(self.lmax + 1): for m in range(2 * l + 1): self.y_Lg.append( np.sqrt(4 * np.pi / (2 * l + 1)) * r_g**l * npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2])) self.l_L.append(l) L += 1
def initialize(self, gd): """Initialize Y_L arrays""" self.gd = gd r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78) r_g = np.sqrt(r2_g) rhat_cg = r_cg / r_g self.l_L = [] self.y_Lg = [] npY = np.vectorize(Y, (float,), 'spherical harmonic') L = 0 for l in range(self.lmax + 1): for m in range(2 * l + 1): self.y_Lg.append( np.sqrt(4 * np.pi / (2 * l + 1)) * r_g ** l * npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2]) ) self.l_L.append(l) L += 1
def initialize(self): """Initialize grids.""" center = self.center Rmax = self.Rmax dR = self.dR gd = self.gd nL = len(self.L_l) # initialize the ylm and Radial grids # self.V_R will contain the volume of the R shell # self.R_g will contain the radial indicees corresponding to # each grid point # self.ball_g will contain the mask of the ball of radius Rmax # self.y_Lg will contain the YL values corresponding to # each grid point V_R = np.zeros((int(Rmax / dR + 1),)) npY = np.vectorize(Y, (float,), 'spherical harmonic') r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78) r_g = np.sqrt(r2_g) rhat_cg = r_cg / r_g ball_g = np.where(r_g < Rmax, 1, 0) R_g = np.where(r_g < Rmax, r_g / dR, -1).astype(int) y_Lg = [] for L in range(nL): y_Lg.append(npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2])) for i, v in enumerate(V_R): V_R[i] = np.where(R_g == i, 1, 0).sum() gd.comm.sum(V_R) self.R_g = R_g self.ball_g = ball_g self.V_R = V_R * gd.dv self.y_Lg = y_Lg
def initialize(self): """Initialize grids.""" center = self.center Rmax = self.Rmax dR = self.dR gd = self.gd nL = len(self.L_l) # initialize the ylm and Radial grids # self.V_R will contain the volume of the R shell # self.R_g will contain the radial indicees corresponding to # each grid point # self.ball_g will contain the mask of the ball of radius Rmax # self.y_Lg will contain the YL values corresponding to # each grid point V_R = np.zeros((int(Rmax / dR + 1), )) npY = np.vectorize(Y, (float, ), 'spherical harmonic') r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78) r_g = np.sqrt(r2_g) rhat_cg = r_cg / r_g ball_g = np.where(r_g < Rmax, 1, 0) R_g = np.where(r_g < Rmax, r_g / dR, -1).astype(int) y_Lg = [] for L in range(nL): y_Lg.append(npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2])) for i, v in enumerate(V_R): V_R[i] = np.where(R_g == i, 1, 0).sum() gd.comm.sum(V_R) self.R_g = R_g self.ball_g = ball_g self.V_R = V_R * gd.dv self.y_Lg = y_Lg
def get_effective_volume_ratio(self, atom_index): """Effective volume to free volume ratio. After: Tkatchenko and Scheffler PRL 102 (2009) 073005 """ atoms = self.atoms finegd = self.gd den_g, gd = self.calculator.density.get_all_electron_density(atoms) assert(gd == finegd) denfree_g, gd = self.hdensity.get_density([atom_index]) assert(gd == finegd) # the atoms r^3 grid position = self.atoms[atom_index].position / Bohr r_vg, r2_g = coordinates(finegd, origin=position) r3_g = r2_g * np.sqrt(r2_g) weight_g = np.where(self.atom_index == atom_index, 1.0, 0.0) nom = finegd.integrate(r3_g * den_g[0] * weight_g) denom = finegd.integrate(r3_g * denfree_g) return nom / denom
def calculate(self): # Check that kss_list is up-to-date if not self.kss_list_ready: self.update_list() self.kss_prop_ready = False # Check if we already have properties for all singles if self.kss_prop_ready: return self.kss_prop_ready = True for kss_ip in self.kss_list: if kss_ip.dip_mom_r is None or kss_ip.magn_mom is None: self.kss_prop_ready = False break # If had, done if self.kss_prop_ready: return #self.timer.start('Calculate KS properties') # Init pair densities dnt_Gip = self.calc.wfs.gd.empty() dnt_gip = self.calc.density.finegd.empty() drhot_gip = self.calc.density.finegd.empty() # Init gradients of wfs grad_psit2_G = [ self.calc.wfs.gd.empty(), self.calc.wfs.gd.empty(), self.calc.wfs.gd.empty() ] # Init gradient operators grad = [] dtype = pick(self.calc.wfs.kpt_u[self.kpt_ind].psit_nG, 0).dtype for c in range(3): grad.append(Gradient(self.calc.wfs.gd, c, dtype=dtype, n=2)) # Coordinate vector r R0 = 0.5 * np.diag(self.calc.wfs.gd.cell_cv) # R0 = np.array([0.0,0.0,0.0]) # old_version #print 'R0', R0 r_cG, r2_G = coordinates(self.calc.wfs.gd, origin=R0) r_cg, r2_g = coordinates(self.calc.density.finegd, origin=R0) # Loop over all KS single excitations # # Transition dipole moment, mu_ip = <p| (-e r) |i> # Magnetic transition dipole, m_ip = -(1/2c) <i|L|p> # For total m_0I = -m_I0 = -(m_0I)^*, but not for m_ip (right?) # R_0I = Im[mu_0I * m_0I] # mu_ip^0I = omega_0I^(-1/2) D_ip S^(-1/2) F_0I # m_ip^0I = -omega_0I^(+1/2) M_ip C^-1 S^(+1/2) F_0I # # S_ip,ip = - (eps_p - eps_i) / (n_p - n_i) (note: n_p < n_i) # C_ip,ip = 1 / (n_p - n_i) # # See: # WIREs Comput Mol Sci 2012, 2: 150-166 doi: 10.1002/wcms.55 # J. Chem. Phys., Vol. 116, 6930 (2002) for kss_ip in self.kss_list: # If have dipole moment and magnetic moment, already done and skip if (kss_ip.dip_mom_r is not None and kss_ip.magn_mom is not None): continue # Transition dipole moment, mu_ip = <p| (-r) |i> kss_ip.calculate_pair_density(dnt_Gip, dnt_gip, drhot_gip) #kss_ip.dip_mom_r = self.calc.density.finegd.calculate_dipole_moment(drhot_gip) #kss_ip.dip_mom_r = self.calc.density.finegd.calculate_dipole_moment(drhot_gip) kss_ip.dip_mom_r = np.zeros(3) kss_ip.dip_mom_r[0] = -self.calc.density.finegd.integrate( r_cg[0] * drhot_gip) kss_ip.dip_mom_r[1] = -self.calc.density.finegd.integrate( r_cg[1] * drhot_gip) kss_ip.dip_mom_r[2] = -self.calc.density.finegd.integrate( r_cg[2] * drhot_gip) # Magnetic transition dipole, m_ip = -(1/2c) <i|L|p> = i/2c <i|r x p|p> # see Autschbach et al., J. Chem. Phys., 116, 6930 (2002) # Gradients for c in range(3): grad[c].apply(kss_ip.pair_density.psit2_G, grad_psit2_G[c], self.calc.wfs.kpt_u[self.kpt_ind].phase_cd) # <psi1|r x grad|psi2> # i j k # x y z = (y pz - z py)i + (z px - x pz)j + (x py - y px) # px py pz rxnabla_g = np.zeros(3) rxnabla_g[0] = self.calc.wfs.gd.integrate( kss_ip.pair_density.psit1_G * (r_cG[1] * grad_psit2_G[2] - r_cG[2] * grad_psit2_G[1])) rxnabla_g[1] = self.calc.wfs.gd.integrate( kss_ip.pair_density.psit1_G * (r_cG[2] * grad_psit2_G[0] - r_cG[0] * grad_psit2_G[2])) rxnabla_g[2] = self.calc.wfs.gd.integrate( kss_ip.pair_density.psit1_G * (r_cG[0] * grad_psit2_G[1] - r_cG[1] * grad_psit2_G[0])) # augmentation contributions to magnetic moment # <psi1| r x nabla |psi2> = <psi1| (r-Ra+Ra) x nabla |psi2> # = <psi1| (r-Ra) x nabla |psi2> + Ra x <psi1| nabla |psi2> rxnabla_a = np.zeros(3) # <psi1| (r-Ra) x nabla |psi2> for a, P_ni in self.calc.wfs.kpt_u[self.kpt_ind].P_ani.items(): Pi_i = P_ni[kss_ip.occ_ind] Pp_i = P_ni[kss_ip.unocc_ind] rxnabla_iiv = self.calc.wfs.setups[a].rxnabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pp in enumerate(Pp_i): rxnabla_a[c] += Pi * Pp * rxnabla_iiv[i1, i2, c] self.calc.wfs.gd.comm.sum(rxnabla_a) # sum up from different procs # Ra x <psi1| nabla |psi2> Rxnabla_a = np.zeros(3) for a, P_ni in self.calc.wfs.kpt_u[self.kpt_ind].P_ani.items(): Pi_i = P_ni[kss_ip.occ_ind] Pp_i = P_ni[kss_ip.unocc_ind] nabla_iiv = self.calc.wfs.setups[a].nabla_iiv Ra = (self.calc.atoms[a].position / ase.units.Bohr) - R0 for i1, Pi in enumerate(Pi_i): for i2, Pp in enumerate(Pp_i): # (y pz - z py)i + (z px - x pz)j + (x py - y px)k Rxnabla_a[0] += Pi * Pp * ( Ra[1] * nabla_iiv[i1, i2, 2] - Ra[2] * nabla_iiv[i1, i2, 1]) Rxnabla_a[1] += Pi * Pp * ( Ra[2] * nabla_iiv[i1, i2, 0] - Ra[0] * nabla_iiv[i1, i2, 2]) Rxnabla_a[2] += Pi * Pp * ( Ra[0] * nabla_iiv[i1, i2, 1] - Ra[1] * nabla_iiv[i1, i2, 0]) self.calc.wfs.gd.comm.sum(Rxnabla_a) # sum up from different procs #print (kss_ip.occ_ind, kss_ip.unocc_ind), kss_ip.dip_mom_r, rxnabla_g, rxnabla_a, Rxnabla_a # m_ip = -1/2c <i|r x p|p> = i/2c <i|r x nabla|p> # just imaginary part!!! kss_ip.magn_mom = ase.units.alpha / 2. * (rxnabla_g + rxnabla_a + Rxnabla_a) # Wait... to avoid io problems, and write KS_singles file self.lr_comms.parent_comm.barrier() if self.lr_comms.parent_comm.rank == 0: self.kss_file = open(self.basefilename + '.KS_singles', 'w') for kss_ip in self.kss_list: format = '%08d %08d %18.12lf %18.12lf ' format += '%18.12lf %18.12lf %18.12lf ' format += '%18.12lf %18.12lf %18.12lf\n' self.kss_file.write( format % (kss_ip.occ_ind, kss_ip.unocc_ind, kss_ip.energy_diff, kss_ip.pop_diff, kss_ip.dip_mom_r[0], kss_ip.dip_mom_r[1], kss_ip.dip_mom_r[2], kss_ip.magn_mom[0], kss_ip.magn_mom[1], kss_ip.magn_mom[2])) self.kss_file.close() self.lr_comms.parent_comm.barrier() self.kss_prop_ready = True # avoid repeated work
from gpaw.poisson import PoissonSolver def norm(a): return np.sqrt(np.sum(a.ravel()**2)) / len(a.ravel()) # Initialize classes a = 20 # Size of cell N = 48 # Number of grid points Nc = (N, N, N) # Number of grid points along each axis gd = GridDescriptor(Nc, (a, a, a), 0) # Grid-descriptor object solver = PoissonSolver(nn=3) # Numerical poisson solver solver.set_grid_descriptor(gd) solve = solver.solve xyz, r2 = coordinates(gd) # Matrix with the square of the radial coordinate print(r2.shape) r = np.sqrt(r2) # Matrix with the values of the radial coordinate nH = np.exp(-2 * r) / pi # Density of the hydrogen atom gauss = Gaussian(gd) # An instance of Gaussian # /------------------------------------------------\ # | Check if Gaussian densities are made correctly | # \------------------------------------------------/ for gL in range(2, 9): g = gauss.get_gauss(gL) # a gaussian of gL'th order print('\nGaussian of order', gL) for mL in range(9): m = gauss.get_moment(g, mL) # the mL'th moment of g print(' %s\'th moment = %2.6f' % (mL, m)) equal(m, gL == mL, 1e-4)
def __init__(self, iidx=None, jidx=None, pspin=None, kpt=None, paw=None, string=None, fijscale=1, dtype=float): if string is not None: self.fromstring(string, dtype) return None # normal entry PairDensity.__init__(self, paw) PairDensity.initialize(self, kpt, iidx, jidx) self.pspin = pspin self.energy = 0.0 self.fij = 0.0 self.me = np.zeros((3), dtype=dtype) self.mur = np.zeros((3), dtype=dtype) self.muv = np.zeros((3), dtype=dtype) self.magn = np.zeros((3), dtype=dtype) self.kpt_comm = paw.wfs.kd.comm # leave empty if not my kpt if kpt is None: return wfs = paw.wfs gd = wfs.gd self.energy = kpt.eps_n[jidx] - kpt.eps_n[iidx] self.fij = (kpt.f_n[iidx] - kpt.f_n[jidx]) * fijscale # calculate matrix elements ----------- # length form .......................... # course grid contribution # <i|r|j> is the negative of the dipole moment (because of negative # e- charge) me = -gd.calculate_dipole_moment(self.get()) # augmentation contributions ma = np.zeros(me.shape, dtype=dtype) pos_av = paw.atoms.get_positions() / Bohr for a, P_ni in kpt.P_ani.items(): Ra = pos_av[a] Pi_i = P_ni[self.i].conj() Pj_i = P_ni[self.j] Delta_pL = wfs.setups[a].Delta_pL ni = len(Pi_i) ma0 = 0 ma1 = np.zeros(me.shape, dtype=me.dtype) for i in range(ni): for j in range(ni): pij = Pi_i[i] * Pj_i[j] ij = packed_index(i, j, ni) # L=0 term ma0 += Delta_pL[ij, 0] * pij # L=1 terms if wfs.setups[a].lmax >= 1: # see spherical_harmonics.py for # L=1:y L=2:z; L=3:x ma1 += np.array([ Delta_pL[ij, 3], Delta_pL[ij, 1], Delta_pL[ij, 2] ]) * pij ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0 gd.comm.sum(ma) self.me = sqrt(self.energy * self.fij) * (me + ma) self.mur = -(me + ma) # velocity form ............................. if self.lcao: # XXX Velocity form not supported in LCAO return me = np.zeros(self.mur.shape, dtype=dtype) # get derivatives dtype = self.wfj.dtype dwfj_cg = gd.empty((3), dtype=dtype) if not hasattr(gd, 'ddr'): gd.ddr = [Gradient(gd, c, dtype=dtype).apply for c in range(3)] for c in range(3): gd.ddr[c](self.wfj, dwfj_cg[c], kpt.phase_cd) me[c] = gd.integrate(self.wfi.conj() * dwfj_cg[c]) if 0: me2 = np.zeros(self.mur.shape) for c in range(3): gd.ddr[c](self.wfi, dwfj_cg[c], kpt.phase_cd) me2[c] = gd.integrate(self.wfj * dwfj_cg[c]) print(me, -me2, me2 + me) # augmentation contributions ma = np.zeros(me.shape, dtype=me.dtype) for a, P_ni in kpt.P_ani.items(): Pi_i = P_ni[self.i].conj() Pj_i = P_ni[self.j] nabla_iiv = paw.wfs.setups[a].nabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pj in enumerate(Pj_i): ma[c] += Pi * Pj * nabla_iiv[i1, i2, c] gd.comm.sum(ma) self.muv = -(me + ma) / self.energy # magnetic transition dipole ................ r_cg, r2_g = coordinates(gd) magn = np.zeros(me.shape, dtype=dtype) wfi_g = self.wfi.conj() for ci in range(3): cj = (ci + 1) % 3 ck = (ci + 2) % 3 magn[ci] = gd.integrate(wfi_g * r_cg[cj] * dwfj_cg[ck] - wfi_g * r_cg[ck] * dwfj_cg[cj]) # augmentation contributions ma = np.zeros(magn.shape, dtype=magn.dtype) for a, P_ni in kpt.P_ani.items(): Pi_i = P_ni[self.i].conj() Pj_i = P_ni[self.j] rnabla_iiv = paw.wfs.setups[a].rnabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pj in enumerate(Pj_i): ma[c] += Pi * Pj * rnabla_iiv[i1, i2, c] gd.comm.sum(ma) self.magn = -alpha / 2. * (magn + ma)
def norm(a): return np.sqrt(np.sum(a.ravel() ** 2)) / len(a.ravel()) # Initialize classes a = 20 # Size of cell N = 48 # Number of grid points Nc = (N, N, N) # Number of grid points along each axis gd = GridDescriptor(Nc, (a, a, a), 0) # Grid-descriptor object solver = PoissonSolver(nn=3) # Numerical poisson solver solver.set_grid_descriptor(gd) solver.initialize() solve = solver.solve xyz, r2 = coordinates(gd) # Matrix with the square of the radial coordinate print(r2.shape) r = np.sqrt(r2) # Matrix with the values of the radial coordinate nH = np.exp(-2 * r) / pi # Density of the hydrogen atom gauss = Gaussian(gd) # An instance of Gaussian # /------------------------------------------------\ # | Check if Gaussian densities are made correctly | # \------------------------------------------------/ for gL in range(2, 9): g = gauss.get_gauss(gL) # a gaussian of gL'th order print("\nGaussian of order", gL) for mL in range(9): m = gauss.get_moment(g, mL) # the mL'th moment of g print(" %s'th moment = %2.6f" % (mL, m)) equal(m, gL == mL, 1e-4)
def __init__(self, iidx=None, jidx=None, pspin=None, kpt=None, paw=None, string=None, fijscale=1): if string is not None: self.fromstring(string) return None # normal entry PairDensity.__init__(self, paw) wfs = paw.wfs PairDensity.initialize(self, kpt, iidx, jidx) self.pspin=pspin f = kpt.f_n self.fij = (f[iidx] - f[jidx]) * fijscale e = kpt.eps_n self.energy = e[jidx] - e[iidx] # calculate matrix elements ----------- gd = wfs.gd self.gd = gd # length form .......................... # course grid contribution # <i|r|j> is the negative of the dipole moment (because of negative # e- charge) me = - gd.calculate_dipole_moment(self.get()) # augmentation contributions ma = np.zeros(me.shape) pos_av = paw.atoms.get_positions() / Bohr for a, P_ni in kpt.P_ani.items(): Ra = pos_av[a] Pi_i = P_ni[self.i] Pj_i = P_ni[self.j] Delta_pL = wfs.setups[a].Delta_pL ni=len(Pi_i) ma0 = 0 ma1 = np.zeros(me.shape) for i in range(ni): for j in range(ni): pij = Pi_i[i]*Pj_i[j] ij = packed_index(i, j, ni) # L=0 term ma0 += Delta_pL[ij,0]*pij # L=1 terms if wfs.setups[a].lmax >= 1: # see spherical_harmonics.py for # L=1:y L=2:z; L=3:x ma1 += np.array([Delta_pL[ij,3], Delta_pL[ij,1], Delta_pL[ij,2]]) * pij ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0 gd.comm.sum(ma) self.me = sqrt(self.energy * self.fij) * ( me + ma ) self.mur = - ( me + ma ) # velocity form ............................. me = np.zeros(self.mur.shape) # get derivatives dtype = self.wfj.dtype dwfj_cg = gd.empty((3), dtype=dtype) if not hasattr(gd, 'ddr'): gd.ddr = [Gradient(gd, c, dtype=dtype).apply for c in range(3)] for c in range(3): gd.ddr[c](self.wfj, dwfj_cg[c], kpt.phase_cd) me[c] = gd.integrate(self.wfi * dwfj_cg[c]) if 0: me2 = np.zeros(self.mur.shape) for c in range(3): gd.ddr[c](self.wfi, dwfj_cg[c], kpt.phase_cd) me2[c] = gd.integrate(self.wfj * dwfj_cg[c]) print me, -me2, me2+me # augmentation contributions ma = np.zeros(me.shape) for a, P_ni in kpt.P_ani.items(): Pi_i = P_ni[self.i] Pj_i = P_ni[self.j] nabla_iiv = paw.wfs.setups[a].nabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pj in enumerate(Pj_i): ma[c] += Pi * Pj * nabla_iiv[i1, i2, c] gd.comm.sum(ma) self.muv = - (me + ma) / self.energy ## print self.mur, self.muv, self.mur - self.muv # magnetic transition dipole ................ magn = np.zeros(me.shape) r_cg, r2_g = coordinates(gd) wfi_g = self.wfi for ci in range(3): cj = (ci + 1) % 3 ck = (ci + 2) % 3 magn[ci] = gd.integrate(wfi_g * r_cg[cj] * dwfj_cg[ck] - wfi_g * r_cg[ck] * dwfj_cg[cj] ) # augmentation contributions ma = np.zeros(magn.shape) for a, P_ni in kpt.P_ani.items(): Pi_i = P_ni[self.i] Pj_i = P_ni[self.j] rnabla_iiv = paw.wfs.setups[a].rnabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pj in enumerate(Pj_i): ma[c] += Pi * Pj * rnabla_iiv[i1, i2, c] gd.comm.sum(ma) self.magn = -alpha / 2. * (magn + ma)
def __init__(self, gd, a=19., center=None): self.gd = gd self.xyz, self.r2 = coordinates(gd, center) self.set_width(a)