def set_grid_descriptor(self, gd): self.gd = gd self.gds = [gd] self.dv = gd.dv gd = self.gd self.B = None self.interpolators = [] self.restrictors = [] self.operators = [] level = 0 self.presmooths = [2] self.postsmooths = [1] self.weights = [2. / 3.] while level < 8: try: gd2 = gd.coarsen() except ValueError: break self.gds.append(gd2) self.interpolators.append(Transformer(gd2, gd)) self.restrictors.append(Transformer(gd, gd2)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level
def go(comm, ngpts, repeat, narrays, out, prec): N_c = np.array((ngpts, ngpts, ngpts)) a = 10.0 gd = GridDescriptor(N_c, (a, a, a), comm=comm)) gdcoarse = gd.coarsen() gdfine = gd.refine() kin1 = Laplace(gd, -0.5, 1).apply laplace = Laplace(gd, -0.5, 2) kin2 = laplace.apply restrict = Transformer(gd, gdcoarse, 1).apply interpolate = Transformer(gd, gdfine, 1).apply precondition = Preconditioner(gd, laplace, np_float) a1 = gd.empty(narrays) a1[:] = 1.0 a2 = gd.empty(narrays) c = gdcoarse.empty(narrays) f = gdfine.empty(narrays) T = [0, 0, 0, 0, 0] for i in range(repeat): comm.barrier() kin1(a1, a2) comm.barrier() t0a = time() kin1(a1, a2) t0b = time() comm.barrier() t1a = time() kin2(a1, a2) t1b = time() comm.barrier() t2a = time() for A, C in zip(a1,c): restrict(A, C) t2b = time() comm.barrier() t3a = time() for A, F in zip(a1,f): interpolate(A, F) t3b = time() comm.barrier() if prec: t4a = time() for A in a1: precondition(A, None, None, None) t4b = time() comm.barrier() T[0] += t0b - t0a T[1] += t1b - t1a T[2] += t2b - t2a T[3] += t3b - t3a if prec: T[4] += t4b - t4a if mpi.rank == 0: out.write(' %2d %2d %2d' % tuple(gd.parsize_c)) out.write(' %12.6f %12.6f %12.6f %12.6f %12.6f\n' % tuple([t / repeat / narrays for t in T])) out.flush()
def set_grid_descriptor(self, gd): # Should probably be renamed initialize self.gd = gd scale = -0.25 / pi if self.nn == 'M': if not gd.orthogonal: raise RuntimeError('Cannot use Mehrstellen stencil with ' 'non orthogonal cell.') self.operators = [LaplaceA(gd, -scale)] self.B = LaplaceB(gd) else: self.operators = [Laplace(gd, scale, self.nn)] self.B = None self.interpolators = [] self.restrictors = [] level = 0 self.presmooths = [2] self.postsmooths = [1] # Weights for the relaxation, # only used if 'J' (Jacobi) is chosen as method self.weights = [2.0 / 3.0] while level < 8: try: gd2 = gd.coarsen() except ValueError: break self.operators.append(Laplace(gd2, scale, 1)) self.interpolators.append(Transformer(gd2, gd)) self.restrictors.append(Transformer(gd, gd2)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level if self.operators[-1].gd.N_c.max() > 36: # Try to warn exactly once no matter how one uses the solver. if gd.comm.parent is None: warn = (gd.comm.rank == 0) else: warn = (gd.comm.parent.rank == 0) if warn: warntxt = '\n'.join([POISSON_GRID_WARNING, '', self.get_description()]) else: warntxt = ('Poisson warning from domain rank %d' % self.gd.comm.rank) # Warn from all ranks to avoid deadlocks. warnings.warn(warntxt, stacklevel=2)
def get_combined_data(self, qmdata=None, cldata=None, spacing=None): if qmdata is None: qmdata = self.density.rhot_g if cldata is None: cldata = self.classical_material.charge_density if spacing is None: spacing = self.cl.gd.h_cv[0, 0] spacing_au = spacing / Bohr # from Angstroms to a.u. # Collect data from different processes cln = self.cl.gd.collect(cldata) qmn = self.qm.gd.collect(qmdata) clgd = GridDescriptor(self.cl.gd.N_c, self.cl.cell, False, serial_comm, None) if world.rank == 0: cln *= self.classical_material.sign # refine classical part while clgd.h_cv[0, 0] > spacing_au * 1.50: # 45: cln = Transformer(clgd, clgd.refine()).apply(cln) clgd = clgd.refine() # refine quantum part qmgd = GridDescriptor(self.qm.gd.N_c, self.qm.cell, False, serial_comm, None) while qmgd.h_cv[0, 0] < clgd.h_cv[0, 0] * 0.95: qmn = Transformer(qmgd, qmgd.coarsen()).apply(qmn) qmgd = qmgd.coarsen() assert np.all(qmgd.h_cv == clgd.h_cv ), " Spacings %.8f (qm) and %.8f (cl) Angstroms" % ( qmgd.h_cv[0][0] * Bohr, clgd.h_cv[0][0] * Bohr) # now find the corners r_gv_cl = clgd.get_grid_point_coordinates().transpose((1, 2, 3, 0)) cind = self.qm.corner1 / np.diag(clgd.h_cv) - 1 n = qmn.shape # print 'Corner points: ', self.qm.corner1*Bohr, ' - ', self.qm.corner2*Bohr # print 'Calculated points: ', r_gv_cl[tuple(cind)]*Bohr, ' - ', r_gv_cl[tuple(cind+n+1)]*Bohr cln[cind[0] + 1:cind[0] + n[0] + 1, cind[1] + 1:cind[1] + n[1] + 1, cind[2] + 1:cind[2] + n[2] + 1] += qmn world.barrier() return cln, clgd
def initialize(self, density, hamiltonian, wfs, occupations): assert wfs.kd.gamma self.xc.initialize(density, hamiltonian, wfs, occupations) self.kpt_comm = wfs.kd.comm self.nspins = wfs.nspins self.setups = wfs.setups self.density = density self.kpt_u = wfs.kpt_u self.exx_s = np.zeros(self.nspins) self.ekin_s = np.zeros(self.nspins) self.nocc_s = np.empty(self.nspins, int) self.gd = density.gd self.redistributor = density.redistributor use_charge_center = hamiltonian.poisson.use_charge_center # XXX How do we construct a copy of the Poisson solver of the # Hamiltonian? We don't know what class it is, etc., but gd # may differ. # XXX One might consider using a charged centered compensation # charge for the PoissonSolver in the case of EXX as standard self.poissonsolver = PoissonSolver('fd', eps=1e-11, use_charge_center=use_charge_center) # self.poissonsolver = hamiltonian.poisson if self.finegrid: self.finegd = self.gd.refine() # XXX Taking restrictor from Hamiltonian will not work in PW mode, # will it? I think this supports only real-space mode. # self.restrictor = hamiltonian.restrictor self.restrictor = Transformer(self.finegd, self.gd, 3) self.interpolator = Transformer(self.gd, self.finegd, 3) else: self.finegd = self.gd self.ghat = LFC(self.finegd, [setup.ghat_l for setup in density.setups], integral=np.sqrt(4 * np.pi), forces=True) self.poissonsolver.set_grid_descriptor(self.finegd) if self.rsf == 'Yukawa': omega2 = self.omega**2 self.screened_poissonsolver = HelmholtzSolver( k2=-omega2, eps=1e-11, nn=3, use_charge_center=use_charge_center) self.screened_poissonsolver.set_grid_descriptor(self.finegd)
def __init__(self, gd, finegd, nspins, setups, timer, xc, world, kptband_comm, vext=None, collinear=True, psolver=None, stencil=3): Hamiltonian.__init__(self, gd, finegd, nspins, setups, timer, xc, world, kptband_comm, vext, collinear) # Solver for the Poisson equation: if psolver is None: psolver = PoissonSolver(nn=3, relax='J') self.poisson = psolver self.poisson.set_grid_descriptor(finegd) # Restrictor function for the potential: self.restrictor = Transformer(self.finegd, self.gd, stencil) self.restrict = self.restrictor.apply self.vbar = LFC(self.finegd, [[setup.vbar] for setup in setups], forces=True) self.vbar_g = None
def interpolate_pseudo_density(self, gridrefinement=2): gd = self.gd Fnt_wsg = self.Fnt_wsG.copy() # Find m for # gridrefinement = 2**m m1 = np.log(gridrefinement) / np.log(2.) m = int(np.round(m1)) # Check if m is really integer if np.absolute(m - m1) < 1e-8: for i in range(m): gd2 = gd.refine() # Interpolate interpolator = Transformer(gd, gd2, self.stencil, dtype=self.dtype) Fnt2_wsg = gd2.empty((self.nw, self.nspins), dtype=self.dtype) for w in range(self.nw): for s in range(self.nspins): interpolator.apply(Fnt_wsg[w][s], Fnt2_wsg[w][s], np.ones((3, 2), dtype=complex)) gd = gd2 Fnt_wsg = Fnt2_wsg else: raise NotImplementedError return Fnt_wsg, gd
def writearray(name): if name.split('_')[0] in writes: a_xg = getattr(self, name) if self.fdtd.cl.gd != self.gd: a_xg = Transformer(self.fdtd.cl.gd, self.gd, self.stencil, a_xg.dtype).apply(a_xg) writer.write(**{name: self.gd.collect(a_xg)})
def initialize(self, paw, allocate=True): self.allocated = False assert hasattr(paw, 'time') and hasattr(paw, 'niter'), 'Use TDDFT!' self.time = paw.time self.niter = paw.niter self.world = paw.wfs.world self.gd = paw.density.gd self.finegd = paw.density.finegd self.nspins = paw.density.nspins self.stencil = paw.input_parameters.stencils[ 1] # i.e. tar['InterpolationStencil'] self.interpolator = paw.density.interpolator self.cinterpolator = Transformer(self.gd, self.finegd, self.stencil, \ dtype=self.dtype) self.phase_cd = np.ones((3, 2), dtype=complex) self.Ant_sG = paw.density.nt_sG.copy() # TODO in allocate instead? # Attach to PAW-type object paw.attach(self, self.interval, density=paw.density) if allocate: self.allocate()
def set_grid_descriptor(self, gd): # Should probably be renamed initialize self.gd = gd self.dv = gd.dv gd = self.gd scale = -0.25 / pi if self.nn == 'M': raise ValueError('Helmholtz not defined for Mehrstellen stencil') self.operators = [HelmholtzOperator(gd, scale, self.nn, k2=self.k2)] self.B = None self.interpolators = [] self.restrictors = [] level = 0 self.presmooths = [2] self.postsmooths = [1] # Weights for the relaxation, # only used if 'J' (Jacobi) is chosen as method self.weights = [2.0 / 3.0] while level < 4: try: gd2 = gd.coarsen() except ValueError: break self.operators.append(HelmholtzOperator(gd2, scale, 1, k2=self.k2)) self.interpolators.append(Transformer(gd2, gd)) self.restrictors.append(Transformer(gd, gd2)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level if self.relax_method == 1: self.description = 'Gauss-Seidel' else: self.description = 'Jacobi' self.description += ' solver with %d multi-grid levels' % (level + 1) self.description += '\nStencil: ' + self.operators[0].description
def set_grid_descriptor(self, gd): # Should probably be renamed initialize self.gd = gd self.dv = gd.dv gd = self.gd scale = -0.25 / pi if self.nn == 'M': if not gd.orthogonal: raise RuntimeError('Cannot use Mehrstellen stencil with ' 'non orthogonal cell.') self.operators = [LaplaceA(gd, -scale, allocate=False)] self.B = LaplaceB(gd, allocate=False) else: self.operators = [Laplace(gd, scale, self.nn, allocate=False)] self.B = None self.interpolators = [] self.restrictors = [] level = 0 self.presmooths = [2] self.postsmooths = [1] # Weights for the relaxation, # only used if 'J' (Jacobi) is chosen as method self.weights = [2.0 / 3.0] while level < 4: try: gd2 = gd.coarsen() except ValueError: break self.operators.append(Laplace(gd2, scale, 1, allocate=False)) self.interpolators.append(Transformer(gd2, gd, allocate=False)) self.restrictors.append(Transformer(gd, gd2, allocate=False)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level
def __init__(self, gd0, kin0, dtype=float, block=1): gd1 = gd0.coarsen() gd2 = gd1.coarsen() self.kin0 = kin0 self.kin1 = Laplace(gd1, -0.5, 1, dtype) self.kin2 = Laplace(gd2, -0.5, 1, dtype) self.scratch0 = gd0.zeros((2, block), dtype, False) self.scratch1 = gd1.zeros((3, block), dtype, False) self.scratch2 = gd2.zeros((3, block), dtype, False) self.step = 0.66666666 / kin0.get_diagonal_element() self.restrictor_object0 = Transformer(gd0, gd1, 1, dtype) self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype) self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype) self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype) self.restrictor0 = self.restrictor_object0.apply self.restrictor1 = self.restrictor_object1.apply self.interpolator2 = self.interpolator_object2.apply self.interpolator1 = self.interpolator_object1.apply
def get_induced_density(self, from_density, gridrefinement): if self.gd == self.fdtd.cl.gd: Frho_wg = self.Fn_wG.copy() else: Frho_wg = Transformer(self.fdtd.cl.gd, self.gd, self.stencil, dtype=self.dtype).apply(self.Fn_wG) Frho_wg, gd = self.interpolate_density(self.gd, Frho_wg, gridrefinement) return Frho_wg, gd
def interpolate_2d(mat): from gpaw.grid_descriptor import GridDescriptor from gpaw.transformers import Transformer nn = 10 N_c = np.zeros([3], dtype=int) N_c[1:] = mat.shape[:2] N_c[0] = nn bmat = np.resize(mat, N_c) gd = GridDescriptor(N_c, N_c) finegd = GridDescriptor(N_c * 2, N_c) interpolator = Transformer(gd, finegd, 3) fine_bmat = finegd.zeros() interpolator.apply(bmat, fine_bmat) return fine_bmat[0]
def initialize(self, density, hamiltonian, wfs, occupations): assert wfs.kd.gamma self.xc.initialize(density, hamiltonian, wfs, occupations) self.kpt_comm = wfs.kd.comm self.nspins = wfs.nspins self.setups = wfs.setups self.density = density self.kpt_u = wfs.kpt_u self.exx_s = np.zeros(self.nspins) self.ekin_s = np.zeros(self.nspins) self.nocc_s = np.empty(self.nspins, int) self.gd = density.gd self.redistributor = density.redistributor # XXX How do we construct a copy of the Poisson solver of the # Hamiltonian? We don't know what class it is, etc., but gd # may differ. self.poissonsolver = PoissonSolver(eps=1e-11) #self.poissonsolver = hamiltonian.poisson if self.finegrid: self.finegd = self.gd.refine() # XXX Taking restrictor from Hamiltonian will not work in PW mode, # will it? I think this supports only real-space mode. #self.restrictor = hamiltonian.restrictor self.restrictor = Transformer(self.finegd, self.gd, 3) self.interpolator = Transformer(self.gd, self.finegd, 3) else: self.finegd = self.gd self.ghat = LFC(self.finegd, [setup.ghat_l for setup in density.setups], integral=np.sqrt(4 * np.pi), forces=True) self.poissonsolver.set_grid_descriptor(self.finegd) self.poissonsolver.initialize()
def initialize(self, setups, timer, magmom_av, hund): Density.initialize(self, setups, timer, magmom_av, hund) # Interpolation function for the density: self.interpolator = Transformer(self.gd, self.finegd, self.stencil) spline_aj = [] for setup in setups: if setup.nct is None: spline_aj.append([]) else: spline_aj.append([setup.nct]) self.nct = LFC(self.gd, spline_aj, integral=[setup.Nct for setup in setups], forces=True, cut=True) self.ghat = LFC(self.finegd, [setup.ghat_l for setup in setups], integral=sqrt(4 * pi), forces=True)
def __init__(self, gd, finegd, nspins, setups, stencil, timer, xc, psolver, vext_g): """Create the Hamiltonian.""" self.gd = gd self.finegd = finegd self.nspins = nspins self.setups = setups self.timer = timer self.xc = xc # Solver for the Poisson equation: if psolver is None: psolver = PoissonSolver(nn=3, relax='J') self.poisson = psolver self.poisson.set_grid_descriptor(finegd) self.dH_asp = None # The external potential self.vext_g = vext_g self.vt_sG = None self.vHt_g = None self.vt_sg = None self.vbar_g = None self.rank_a = None # Restrictor function for the potential: self.restrictor = Transformer(self.finegd, self.gd, stencil, allocate=False) self.restrict = self.restrictor.apply self.vbar = LFC(self.finegd, [[setup.vbar] for setup in setups], forces=True) self.Ekin0 = None self.Ekin = None self.Epot = None self.Ebar = None self.Eext = None self.Exc = None self.Etot = None self.S = None self.allocated = False
def __init__(self, gd, finegd, nspins, setups, timer, xc, world, vext=None, psolver=None, stencil=3, redistributor=None): Hamiltonian.__init__(self, gd, finegd, nspins, setups, timer, xc, world, vext=vext, redistributor=redistributor) # Solver for the Poisson equation: if psolver is None: psolver = {} if isinstance(psolver, dict): psolver = create_poisson_solver(**psolver) self.poisson = psolver self.poisson.set_grid_descriptor(self.finegd) # Restrictor function for the potential: self.restrictor = Transformer(self.finegd, self.redistributor.aux_gd, stencil) self.restrict = self.restrictor.apply self.vbar = LFC(self.finegd, [[setup.vbar] for setup in setups], forces=True) self.vbar_g = None
def initialize(self, setups, stencil, timer, magmom_a, hund): self.timer = timer self.setups = setups self.hund = hund self.magmom_a = magmom_a # Interpolation function for the density: self.interpolator = Transformer(self.gd, self.finegd, stencil, allocate=False) spline_aj = [] for setup in setups: if setup.nct is None: spline_aj.append([]) else: spline_aj.append([setup.nct]) self.nct = LFC(self.gd, spline_aj, integral=[setup.Nct for setup in setups], forces=True, cut=True) self.ghat = LFC(self.finegd, [setup.ghat_l for setup in setups], integral=sqrt(4 * pi), forces=True) if self.allocated: self.allocated = False self.allocate()
def get_all_electron_density(self, atoms=None, gridrefinement=2, spos_ac=None, skip_core=False): """Return real all-electron density array. Usage: Either get_all_electron_density(atoms) or get_all_electron_density(spos_ac=spos_ac) skip_core=True theoretically returns the all-electron valence density (use with care; will not in general integrate to valence) """ if spos_ac is None: spos_ac = atoms.get_scaled_positions() % 1.0 # Refinement of coarse grid, for representation of the AE-density # XXXXXXXXXXXX think about distribution depending on gridrefinement! if gridrefinement == 1: gd = self.redistributor.aux_gd n_sg = self.nt_sG.copy() # This will get the density with the same distribution # as finegd: n_sg = self.redistributor.distribute(n_sg) elif gridrefinement == 2: gd = self.finegd if self.nt_sg is None: self.interpolate_pseudo_density() n_sg = self.nt_sg.copy() elif gridrefinement == 4: # Extra fine grid gd = self.finegd.refine() # Interpolation function for the density: interpolator = Transformer(self.finegd, gd, 3) # XXX grids! # Transfer the pseudo-density to the fine grid: n_sg = gd.empty(self.nspins) if self.nt_sg is None: self.interpolate_pseudo_density() for s in range(self.nspins): interpolator.apply(self.nt_sg[s], n_sg[s]) else: raise NotImplementedError # Add corrections to pseudo-density to get the AE-density splines = {} phi_aj = [] phit_aj = [] nc_a = [] nct_a = [] for a, id in enumerate(self.setups.id_a): if id in splines: phi_j, phit_j, nc, nct = splines[id] else: # Load splines: phi_j, phit_j, nc, nct = self.setups[a].get_partial_waves()[:4] splines[id] = (phi_j, phit_j, nc, nct) phi_aj.append(phi_j) phit_aj.append(phit_j) nc_a.append([nc]) nct_a.append([nct]) # Create localized functions from splines phi = BasisFunctions(gd, phi_aj) phit = BasisFunctions(gd, phit_aj) nc = LFC(gd, nc_a) nct = LFC(gd, nct_a) phi.set_positions(spos_ac) phit.set_positions(spos_ac) nc.set_positions(spos_ac) nct.set_positions(spos_ac) I_sa = np.zeros((self.nspins, len(spos_ac))) a_W = np.empty(len(phi.M_W), np.intc) W = 0 for a in phi.atom_indices: nw = len(phi.sphere_a[a].M_w) a_W[W:W + nw] = a W += nw x_W = phi.create_displacement_arrays()[0] D_asp = self.D_asp # XXX really? rho_MM = np.zeros((phi.Mmax, phi.Mmax)) for s, I_a in enumerate(I_sa): M1 = 0 for a, setup in enumerate(self.setups): ni = setup.ni D_sp = D_asp.get(a) if D_sp is None: D_sp = np.empty((self.nspins, ni * (ni + 1) // 2)) else: I_a[a] = ( (setup.Nct) / self.nspins - sqrt(4 * pi) * np.dot(D_sp[s], setup.Delta_pL[:, 0])) if not skip_core: I_a[a] -= setup.Nc / self.nspins if gd.comm.size > 1: gd.comm.broadcast(D_sp, D_asp.partition.rank_a[a]) M2 = M1 + ni rho_MM[M1:M2, M1:M2] = unpack2(D_sp[s]) M1 = M2 assert np.all(n_sg[s].shape == phi.gd.n_c) phi.lfc.ae_valence_density_correction(rho_MM, n_sg[s], a_W, I_a, x_W) phit.lfc.ae_valence_density_correction(-rho_MM, n_sg[s], a_W, I_a, x_W) a_W = np.empty(len(nc.M_W), np.intc) W = 0 for a in nc.atom_indices: nw = len(nc.sphere_a[a].M_w) a_W[W:W + nw] = a W += nw scale = 1.0 / self.nspins for s, I_a in enumerate(I_sa): if not skip_core: nc.lfc.ae_core_density_correction(scale, n_sg[s], a_W, I_a) nct.lfc.ae_core_density_correction(-scale, n_sg[s], a_W, I_a) gd.comm.sum(I_a) N_c = gd.N_c g_ac = np.around(N_c * spos_ac).astype(int) % N_c - gd.beg_c if not skip_core: for I, g_c in zip(I_a, g_ac): if (g_c >= 0).all() and (g_c < gd.n_c).all(): n_sg[s][tuple(g_c)] -= I / gd.dv return n_sg, gd
def new_get_all_electron_density(self, atoms, gridrefinement=2): """Return real all-electron density array.""" # Refinement of coarse grid, for representation of the AE-density if gridrefinement == 1: gd = self.gd n_sg = self.nt_sG.copy() elif gridrefinement == 2: gd = self.finegd if self.nt_sg is None: self.interpolate() n_sg = self.nt_sg.copy() elif gridrefinement == 4: # Extra fine grid gd = self.finegd.refine() # Interpolation function for the density: interpolator = Transformer(self.finegd, gd, 3) # Transfer the pseudo-density to the fine grid: n_sg = gd.empty(self.nspins) if self.nt_sg is None: self.interpolate() for s in range(self.nspins): interpolator.apply(self.nt_sg[s], n_sg[s]) else: raise NotImplementedError # Add corrections to pseudo-density to get the AE-density splines = {} phi_aj = [] phit_aj = [] nc_a = [] nct_a = [] for a, id in enumerate(self.setups.id_a): if id in splines: phi_j, phit_j, nc, nct = splines[id] else: # Load splines: phi_j, phit_j, nc, nct = self.setups[a].get_partial_waves()[:4] splines[id] = (phi_j, phit_j, nc, nct) phi_aj.append(phi_j) phit_aj.append(phit_j) nc_a.append([nc]) nct_a.append([nct]) # Create localized functions from splines phi = BasisFunctions(gd, phi_aj) phit = BasisFunctions(gd, phit_aj) nc = LFC(gd, nc_a) nct = LFC(gd, nct_a) spos_ac = atoms.get_scaled_positions() % 1.0 phi.set_positions(spos_ac) phit.set_positions(spos_ac) nc.set_positions(spos_ac) nct.set_positions(spos_ac) I_sa = np.zeros((self.nspins, len(atoms))) a_W = np.empty(len(phi.M_W), np.int32) W = 0 for a in phi.atom_indices: nw = len(phi.sphere_a[a].M_w) a_W[W:W + nw] = a W += nw rho_MM = np.zeros((phi.Mmax, phi.Mmax)) for s, I_a in enumerate(I_sa): M1 = 0 for a, setup in enumerate(self.setups): ni = setup.ni D_sp = self.D_asp.get(a) if D_sp is None: D_sp = np.empty((self.nspins, ni * (ni + 1) // 2)) else: I_a[a] = ((setup.Nct - setup.Nc) / self.nspins - sqrt(4 * pi) * np.dot(D_sp[s], setup.Delta_pL[:, 0])) if gd.comm.size > 1: gd.comm.broadcast(D_sp, self.rank_a[a]) M2 = M1 + ni rho_MM[M1:M2, M1:M2] = unpack2(D_sp[s]) M1 = M2 phi.lfc.ae_valence_density_correction(rho_MM, n_sg[s], a_W, I_a) phit.lfc.ae_valence_density_correction(-rho_MM, n_sg[s], a_W, I_a) a_W = np.empty(len(nc.M_W), np.int32) W = 0 for a in nc.atom_indices: nw = len(nc.sphere_a[a].M_w) a_W[W:W + nw] = a W += nw scale = 1.0 / self.nspins for s, I_a in enumerate(I_sa): nc.lfc.ae_core_density_correction(scale, n_sg[s], a_W, I_a) nct.lfc.ae_core_density_correction(-scale, n_sg[s], a_W, I_a) gd.comm.sum(I_a) N_c = gd.N_c g_ac = np.around(N_c * spos_ac).astype(int) % N_c - gd.beg_c for I, g_c in zip(I_a, g_ac): if (g_c >= 0).all() and (g_c < gd.n_c).all(): n_sg[s][tuple(g_c)] -= I / gd.dv return n_sg, gd
def __init__(self, calculator=None, kss=None, xc=None, derivativeLevel=None, numscale=0.001, filehandle=None, txt=None, finegrid=2, eh_comm=None, ): if not txt and calculator: txt = calculator.txt self.txt = get_txt(txt, mpi.rank) if eh_comm is None: eh_comm = mpi.serial_comm self.eh_comm = eh_comm if filehandle is not None: self.kss = kss self.read(fh=filehandle) return None self.fullkss = kss self.finegrid = finegrid if calculator is None: return self.paw = calculator wfs = self.paw.wfs # handle different grid possibilities self.restrict = None # self.poisson = PoissonSolver(nn=self.paw.hamiltonian.poisson.nn) self.poisson = calculator.hamiltonian.poisson if finegrid: self.poisson.set_grid_descriptor(self.paw.density.finegd) self.poisson.initialize() self.gd = self.paw.density.finegd if finegrid == 1: self.gd = wfs.gd else: self.poisson.set_grid_descriptor(wfs.gd) self.poisson.initialize() self.gd = wfs.gd self.restrict = Transformer(self.paw.density.finegd, wfs.gd, self.paw.input_parameters.stencils[1] ).apply if xc == 'RPA': xc = None # enable RPA as keyword if xc is not None: self.xc = XC(xc) self.xc.initialize(self.paw.density, self.paw.hamiltonian, wfs, self.paw.occupations) # check derivativeLevel if derivativeLevel is None: derivativeLevel = \ self.xc.get_functional().get_max_derivative_level() self.derivativeLevel = derivativeLevel # change the setup xc functional if needed # the ground state calculation may have used another xc if kss.npspins > kss.nvspins: spin_increased = True else: spin_increased = False else: self.xc = None self.numscale = numscale self.singletsinglet = False if kss.nvspins < 2 and kss.npspins < 2: # this will be a singlet to singlet calculation only self.singletsinglet = True nij = len(kss) self.Om = np.zeros((nij, nij)) self.get_full()
def get_all_electron_density(self, atoms, gridrefinement=2): """Return real all-electron density array.""" # Refinement of coarse grid, for representation of the AE-density if gridrefinement == 1: gd = self.gd n_sg = self.nt_sG.copy() elif gridrefinement == 2: gd = self.finegd if self.nt_sg is None: self.interpolate() n_sg = self.nt_sg.copy() elif gridrefinement == 4: # Extra fine grid gd = self.finegd.refine() # Interpolation function for the density: interpolator = Transformer(self.finegd, gd, 3) # Transfer the pseudo-density to the fine grid: n_sg = gd.empty(self.nspins) if self.nt_sg is None: self.interpolate() for s in range(self.nspins): interpolator.apply(self.nt_sg[s], n_sg[s]) else: raise NotImplementedError # Add corrections to pseudo-density to get the AE-density splines = {} phi_aj = [] phit_aj = [] nc_a = [] nct_a = [] for a, id in enumerate(self.setups.id_a): if id in splines: phi_j, phit_j, nc, nct = splines[id] else: # Load splines: phi_j, phit_j, nc, nct = self.setups[a].get_partial_waves()[:4] splines[id] = (phi_j, phit_j, nc, nct) phi_aj.append(phi_j) phit_aj.append(phit_j) nc_a.append([nc]) nct_a.append([nct]) # Create localized functions from splines phi = LFC(gd, phi_aj) phit = LFC(gd, phit_aj) nc = LFC(gd, nc_a) nct = LFC(gd, nct_a) spos_ac = atoms.get_scaled_positions() % 1.0 phi.set_positions(spos_ac) phit.set_positions(spos_ac) nc.set_positions(spos_ac) nct.set_positions(spos_ac) all_D_asp = [] for a, setup in enumerate(self.setups): D_sp = self.D_asp.get(a) if D_sp is None: ni = setup.ni D_sp = np.empty((self.nspins, ni * (ni + 1) // 2)) if gd.comm.size > 1: gd.comm.broadcast(D_sp, self.rank_a[a]) all_D_asp.append(D_sp) for s in range(self.nspins): I_a = np.zeros(len(atoms)) nc.add1(n_sg[s], 1.0 / self.nspins, I_a) nct.add1(n_sg[s], -1.0 / self.nspins, I_a) phi.add2(n_sg[s], all_D_asp, s, 1.0, I_a) phit.add2(n_sg[s], all_D_asp, s, -1.0, I_a) for a, D_sp in self.D_asp.items(): setup = self.setups[a] I_a[a] -= ((setup.Nc - setup.Nct) / self.nspins + sqrt(4 * pi) * np.dot(D_sp[s], setup.Delta_pL[:, 0])) gd.comm.sum(I_a) N_c = gd.N_c g_ac = np.around(N_c * spos_ac).astype(int) % N_c - gd.beg_c for I, g_c in zip(I_a, g_ac): if (g_c >= 0).all() and (g_c < gd.n_c).all(): n_sg[s][tuple(g_c)] -= I / gd.dv return n_sg, gd
def random_wave_functions(self, nao): """Generate random wave functions.""" gpts = self.gd.N_c[0] * self.gd.N_c[1] * self.gd.N_c[2] if self.bd.nbands < gpts / 64: gd1 = self.gd.coarsen() gd2 = gd1.coarsen() psit_G1 = gd1.empty(dtype=self.dtype) psit_G2 = gd2.empty(dtype=self.dtype) interpolate2 = Transformer(gd2, gd1, 1, self.dtype).apply interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply shape = tuple(gd2.n_c) scale = np.sqrt(12 / abs(np.linalg.det(gd2.cell_cv))) old_state = np.random.get_state() np.random.seed(4 + self.world.rank) for kpt in self.kpt_u: for psit_G in kpt.psit_nG[nao:]: if self.dtype == float: psit_G2[:] = (np.random.random(shape) - 0.5) * scale else: psit_G2.real = (np.random.random(shape) - 0.5) * scale psit_G2.imag = (np.random.random(shape) - 0.5) * scale interpolate2(psit_G2, psit_G1, kpt.phase_cd) interpolate1(psit_G1, psit_G, kpt.phase_cd) np.random.set_state(old_state) elif gpts / 64 <= self.bd.nbands < gpts / 8: gd1 = self.gd.coarsen() psit_G1 = gd1.empty(dtype=self.dtype) interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply shape = tuple(gd1.n_c) scale = np.sqrt(12 / abs(np.linalg.det(gd1.cell_cv))) old_state = np.random.get_state() np.random.seed(4 + self.world.rank) for kpt in self.kpt_u: for psit_G in kpt.psit_nG[nao:]: if self.dtype == float: psit_G1[:] = (np.random.random(shape) - 0.5) * scale else: psit_G1.real = (np.random.random(shape) - 0.5) * scale psit_G1.imag = (np.random.random(shape) - 0.5) * scale interpolate1(psit_G1, psit_G, kpt.phase_cd) np.random.set_state(old_state) else: shape = tuple(self.gd.n_c) scale = np.sqrt(12 / abs(np.linalg.det(self.gd.cell_cv))) old_state = np.random.get_state() np.random.seed(4 + self.world.rank) for kpt in self.kpt_u: for psit_G in kpt.psit_nG[nao:]: if self.dtype == float: psit_G[:] = (np.random.random(shape) - 0.5) * scale else: psit_G.real = (np.random.random(shape) - 0.5) * scale psit_G.imag = (np.random.random(shape) - 0.5) * scale np.random.set_state(old_state)
def __init__(self, calc, wfs, poisson_solver=None, dtype=float, **kwargs): """Store calculator etc. Parameters ---------- calc: Calculator Calculator instance containing a ground-state calculation (calc.set_positions must have been called before this point!). wfs: WaveFunctions Class taking care of wave-functions, projectors, k-point related quantities and symmetries. poisson_solver: PoissonSolver Multigrid or FFT poisson solver (not required if the ``Perturbation`` to be solved for has a ``solve_poisson`` member function). dtype: ... dtype of the density response. """ # Store ground-state quantities self.hamiltonian = calc.hamiltonian self.density = calc.density self.wfs = wfs # Get list of k-point containers self.kpt_u = wfs.kpt_u # Poisson solver if poisson_solver is None: # Solver must be provided by the perturbation self.poisson = None self.solve_poisson = None else: self.poisson = poisson_solver self.solve_poisson = self.poisson.solve_neutral # Store grid-descriptors self.gd = calc.density.gd self.finegd = calc.density.finegd # dtype for ground-state wave-functions self.gs_dtype = calc.wfs.dtype # dtype for the perturbing potential and density self.dtype = dtype # Grid transformer -- convert array from coarse to fine grid self.interpolator = Transformer(self.gd, self.finegd, nn=3, dtype=self.dtype, allocate=False) # Grid transformer -- convert array from fine to coarse grid self.restrictor = Transformer(self.finegd, self.gd, nn=3, dtype=self.dtype, allocate=False) # Sternheimer operator self.sternheimer_operator = None # Krylov solver self.linear_solver = None # Phases for transformer objects - since the perturbation determines # the form of the density response this is obtained from the # perturbation in the ``__call__`` member function below. self.phase_cd = None # Array attributes self.nt1_G = None self.vHXC1_G = None self.nt1_g = None self.vH1_g = None # Perturbation self.perturbation = None # Number of occupied bands nvalence = calc.wfs.nvalence self.nbands = nvalence/2 + nvalence%2 assert self.nbands <= calc.wfs.nbands self.initialized = False self.parameters = {} self.set(**kwargs)
from gpaw.transformers import Transformer import numpy.random as ra from gpaw.grid_descriptor import GridDescriptor p = 0 n = 20 gd1 = GridDescriptor((n, n, n), (8.0, 8.0, 8.0), pbc_c=p) a1 = gd1.zeros() ra.seed(8) a1[:] = ra.random(a1.shape) gd2 = gd1.refine() a2 = gd2.zeros() i = Transformer(gd1, gd2).apply i(a1, a2) assert abs(gd1.integrate(a1) - gd2.integrate(a2)) < 1e-10 r = Transformer(gd2, gd1).apply a2[0] = 0.0 a2[:, 0] = 0.0 a2[:, :, 0] = 0.0 a2[-1] = 0.0 a2[:, -1] = 0.0 a2[:, :, -1] = 0.0 r(a2, a1) assert abs(gd1.integrate(a1) - gd2.integrate(a2)) < 1e-10
def get_combined_data(self, qmdata=None, cldata=None, spacing=None, qmgd=None, clgd=None): if qmdata is None: qmdata = self.density.rhot_g if cldata is None: cldata = (self.classical_material.charge_density * self.classical_material.sign) if qmgd is None: qmgd = self.qm.gd if clgd is None: clgd = self.cl.gd if spacing is None: spacing = clgd.h_cv[0, 0] spacing_au = spacing / Bohr # from Angstroms to a.u. # Refine classical part clgd = clgd.new_descriptor() cl_g = cldata.copy() while clgd.h_cv[0, 0] > spacing_au * 1.50: # 45: clgd2 = clgd.refine() cl_g = Transformer(clgd, clgd2).apply(cl_g) clgd = clgd2 # Coarse quantum part qmgd = qmgd.new_descriptor() qm_g = qmdata.copy() while qmgd.h_cv[0, 0] < clgd.h_cv[0, 0] * 0.95: qmgd2 = qmgd.coarsen() qm_g = Transformer(qmgd, qmgd2).apply(qm_g) qmgd = qmgd2 assert np.all(np.absolute(qmgd.h_cv - clgd.h_cv) < 1e-12), \ " Spacings %.8f (qm) and %.8f (cl) Angstroms" \ % (qmgd.h_cv[0][0] * Bohr, clgd.h_cv[0][0] * Bohr) # Do distribution on master big_cl_g = clgd.collect(cl_g) big_qm_g = qmgd.collect(qm_g, broadcast=True) if clgd.comm.rank == 0: # now find the corners # r_gv_cl = \ # clgd.get_grid_point_coordinates().transpose((1, 2, 3, 0)) cind = (self.qm.corner1 / np.diag(clgd.h_cv) - 1).astype(int) n = big_qm_g.shape # print 'Corner points: ', self.qm.corner1*Bohr, \ # ' - ', self.qm.corner2*Bohr # print 'Calculated points: ', r_gv_cl[tuple(cind)]*Bohr, \ # ' - ', r_gv_cl[tuple(cind+n+1)]*Bohr big_cl_g[cind[0] + 1:cind[0] + n[0] + 1, cind[1] + 1:cind[1] + n[1] + 1, cind[2] + 1:cind[2] + n[2] + 1] += big_qm_g clgd.distribute(big_cl_g, cl_g) return cl_g, clgd
def create_subsystems(self, atoms_in): # Create new Atoms object atoms_out = atoms_in.copy() # New quantum grid self.qm.cell = \ np.diag([(self.shift_indices_2[w] - self.shift_indices_1[w]) * self.cl.spacing[w] for w in range(3)]) self.qm.spacing = self.cl.spacing / self.hratios N_c = get_number_of_grid_points(self.qm.cell, self.qm.spacing) atoms_out.set_cell(np.diag(self.qm.cell) * Bohr) atoms_out.positions = atoms_in.get_positions() - self.qm.corner1 * Bohr msg = self.messages.append msg("Quantum box readjustment:") msg(" Given cell: [%10.5f %10.5f %10.5f]" % tuple(np.diag(atoms_in.get_cell()))) msg(" Given atomic coordinates:") for s, c in zip(atoms_in.get_chemical_symbols(), atoms_in.get_positions()): msg(" %s %10.5f %10.5f %10.5f" % (s, c[0], c[1], c[2])) msg(" Readjusted cell: [%10.5f %10.5f %10.5f]" % tuple(np.diag(atoms_out.get_cell()))) msg(" Readjusted atomic coordinates:") for s, c in zip(atoms_out.get_chemical_symbols(), atoms_out.get_positions()): msg(" %s %10.5f %10.5f %10.5f" % (s, c[0], c[1], c[2])) msg(" Given corner points: " + "(%10.5f %10.5f %10.5f) - (%10.5f %10.5f %10.5f)" % (tuple(np.concatenate((self.given_corner_v1, self.given_corner_v2))))) msg(" Readjusted corner points: " + "(%10.5f %10.5f %10.5f) - (%10.5f %10.5f %10.5f)" % (tuple(np.concatenate((self.qm.corner1, self.qm.corner2)) * Bohr))) msg(" Indices in classical grid: " + "(%10i %10i %10i) - (%10i %10i %10i)" % (tuple(np.concatenate((self.shift_indices_1, self.shift_indices_2))))) msg(" Grid points in classical grid: " + "(%10i %10i %10i)" % (tuple(self.cl.gd.N_c))) msg(" Grid points in quantum grid: " + "(%10i %10i %10i)" % (tuple(N_c))) msg(" Spacings in quantum grid: " + "(%10.5f %10.5f %10.5f)" % (tuple(np.diag(self.qm.cell) * Bohr / N_c))) msg(" Spacings in classical grid: " + "(%10.5f %10.5f %10.5f)" % (tuple(np.diag(self.cl.cell) * Bohr / get_number_of_grid_points(self.cl.cell, self.cl.spacing)))) # msg(" Ratios of cl/qm spacings: " + # "(%10i %10i %10i)" % (tuple(self.hratios))) # msg(" = (%10.2f %10.2f %10.2f)" % # (tuple((np.diag(self.cl.cell) * Bohr / \ # get_number_of_grid_points(self.cl.cell, # self.cl.spacing)) / \ # (np.diag(self.qm.cell) * Bohr / N_c)))) msg(" Needed number of refinements: %10i" % self.num_refinements) # First, create the quantum grid equivalent GridDescriptor # self.cl.subgd. Then coarsen it until its h_cv equals # that of self.cl.gd. Finally, map the points between # clgd and coarsened subgrid. subcell_cv = np.diag(self.qm.corner2 - self.qm.corner1) N_c = get_number_of_grid_points(subcell_cv, self.cl.spacing) N_c = self.shift_indices_2 - self.shift_indices_1 self.cl.subgds = [] self.cl.subgds.append(GridDescriptor(N_c, subcell_cv, False, serial_comm, self.cl.dparsize)) # msg(" N_c/spacing of the subgrid: " + # "%3i %3i %3i / %.4f %.4f %.4f" % # (self.cl.subgds[0].N_c[0], # self.cl.subgds[0].N_c[1], # self.cl.subgds[0].N_c[2], # self.cl.subgds[0].h_cv[0][0] * Bohr, # self.cl.subgds[0].h_cv[1][1] * Bohr, # self.cl.subgds[0].h_cv[2][2] * Bohr)) # msg(" shape from the subgrid: " + # "%3i %3i %3i" % (tuple(self.cl.subgds[0].empty().shape))) self.cl.coarseners = [] self.cl.refiners = [] for n in range(self.num_refinements): self.cl.subgds.append(self.cl.subgds[n].refine()) self.cl.refiners.append(Transformer(self.cl.subgds[n], self.cl.subgds[n + 1])) # msg(" refiners[%i] can perform the transformation " + # "(%3i %3i %3i) -> (%3i %3i %3i)" % (\ # n, # self.cl.subgds[n].empty().shape[0], # self.cl.subgds[n].empty().shape[1], # self.cl.subgds[n].empty().shape[2], # self.cl.subgds[n + 1].empty().shape[0], # self.cl.subgds[n + 1].empty().shape[1], # self.cl.subgds[n + 1].empty().shape[2])) self.cl.coarseners.append(Transformer(self.cl.subgds[n + 1], self.cl.subgds[n])) self.cl.coarseners[:] = self.cl.coarseners[::-1] # Now extend the grid in order to handle # the zero boundary conditions that the refiner assumes # The default interpolation order self.extend_nn = \ Transformer(GridDescriptor([8, 8, 8], [1, 1, 1], False, serial_comm, None), GridDescriptor([8, 8, 8], [1, 1, 1], False, serial_comm, None).coarsen()).nn self.extended_num_indices = self.num_indices + [2, 2, 2] # Center, left, and right points of the suggested quantum grid extended_cp = 0.5 * (np.array(self.given_corner_v1 / Bohr) + np.array(self.given_corner_v2 / Bohr)) extended_lp = extended_cp - 0.5 * (self.extended_num_indices * self.cl.spacing) # extended_rp = extended_cp + 0.5 * (self.extended_num_indices * # self.cl.spacing) # Indices in the classical grid restricting the quantum grid self.extended_shift_indices_1 = \ np.round(extended_lp / self.cl.spacing).astype(int) self.extended_shift_indices_2 = \ self.extended_shift_indices_1 + self.extended_num_indices # msg(' extended_shift_indices_1: %i %i %i' # % (self.extended_shift_indices_1[0], # self.extended_shift_indices_1[1], # self.extended_shift_indices_1[2])) # msg(' extended_shift_indices_2: %i %i %i' # % (self.extended_shift_indices_2[0], # self.extended_shift_indices_2[1], # self.extended_shift_indices_2[2])) # msg(' cl.gd.N_c: %i %i %i' # % (self.cl.gd.N_c[0], self.cl.gd.N_c[1], self.cl.gd.N_c[2])) # Sanity checks assert(all([self.extended_shift_indices_1[w] >= 0 and self.extended_shift_indices_2[w] <= self.cl.gd.N_c[w] for w in range(3)])), \ "Could not find appropriate quantum grid. " + \ "Move it further away from the boundary." # Corner coordinates self.qm.extended_corner1 = \ self.extended_shift_indices_1 * self.cl.spacing self.qm.extended_corner2 = \ self.extended_shift_indices_2 * self.cl.spacing N_c = self.extended_shift_indices_2 - self.extended_shift_indices_1 self.cl.extended_subgds = [] self.cl.extended_refiners = [] extended_subcell_cv = np.diag(self.qm.extended_corner2 - self.qm.extended_corner1) self.cl.extended_subgds.append(GridDescriptor( N_c, extended_subcell_cv, False, serial_comm, None)) for n in range(self.num_refinements): self.cl.extended_subgds.append(self.cl.extended_subgds[n].refine()) self.cl.extended_refiners.append(Transformer( self.cl.extended_subgds[n], self.cl.extended_subgds[n + 1])) # msg(" extended_refiners[%i] can perform the transformation " + # "(%3i %3i %3i) -> (%3i %3i %3i)" # % (n, # self.cl.extended_subgds[n].empty().shape[0], # self.cl.extended_subgds[n].empty().shape[1], # self.cl.extended_subgds[n].empty().shape[2], # self.cl.extended_subgds[n + 1].empty().shape[0], # self.cl.extended_subgds[n + 1].empty().shape[1], # self.cl.extended_subgds[n + 1].empty().shape[2])) # msg(" N_c/spacing of the refined subgrid: " + # "%3i %3i %3i / %.4f %.4f %.4f" # % (self.cl.subgds[-1].N_c[0], # self.cl.subgds[-1].N_c[1], # self.cl.subgds[-1].N_c[2], # self.cl.subgds[-1].h_cv[0][0] * Bohr, # self.cl.subgds[-1].h_cv[1][1] * Bohr, # self.cl.subgds[-1].h_cv[2][2] * Bohr)) # msg(" shape from the refined subgrid: %3i %3i %3i" # % (tuple(self.cl.subgds[-1].empty().shape))) self.extended_deltaIndex = 2**(self.num_refinements) * self.extend_nn # msg(" self.extended_deltaIndex = %i" % self.extended_deltaIndex) qgpts = self.cl.subgds[-1].coarsen().N_c # Assure that one returns to the original shape dmygd = self.cl.subgds[-1].coarsen() for n in range(self.num_refinements - 1): dmygd = dmygd.coarsen() # msg(" N_c/spacing of the coarsened subgrid: " + # "%3i %3i %3i / %.4f %.4f %.4f" # % (dmygd.N_c[0], dmygd.N_c[1], dmygd.N_c[2], # dmygd.h_cv[0][0] * Bohr, # dmygd.h_cv[1][1] * Bohr, # dmygd.h_cv[2][2] * Bohr)) self.has_subsystems = True return atoms_out, self.qm.spacing[0] * Bohr, qgpts
def __init__(self, calc, kd, poisson_solver, dtype=float, **kwargs): """Store useful objects, e.g. lfc's for the various atomic functions. Depending on whether the system is periodic or finite, Poisson's equation is solved with FFT or multigrid techniques, respectively. Parameters ---------- calc: Calculator Ground-state calculation. kd: KPointDescriptor Descriptor for the q-vectors of the dynamical matrix. """ self.kd = kd self.dtype = dtype self.poisson = poisson_solver # Gamma wrt q-vector if self.kd.gamma: self.phase_cd = None else: assert self.kd.mynks == len(self.kd.ibzk_qc) self.phase_qcd = [] sdisp_cd = calc.wfs.gd.sdisp_cd for q in range(self.kd.mynks): phase_cd = np.exp(2j * np.pi * \ sdisp_cd * self.kd.ibzk_qc[q, :, np.newaxis]) self.phase_qcd.append(phase_cd) # Store grid-descriptors self.gd = calc.density.gd self.finegd = calc.density.finegd # Steal setups for the lfc's setups = calc.wfs.setups # Store projector coefficients self.dH_asp = calc.hamiltonian.dH_asp.copy() # Localized functions: # core corections self.nct = LFC(self.gd, [[setup.nct] for setup in setups], integral=[setup.Nct for setup in setups], dtype=self.dtype) # compensation charges #XXX what is the consequence of numerical errors in the integral ?? self.ghat = LFC(self.finegd, [setup.ghat_l for setup in setups], dtype=self.dtype) ## self.ghat = LFC(self.finegd, [setup.ghat_l for setup in setups], ## integral=sqrt(4 * pi), dtype=self.dtype) # vbar potential self.vbar = LFC(self.finegd, [[setup.vbar] for setup in setups], dtype=self.dtype) # Expansion coefficients for the compensation charges self.Q_aL = calc.density.Q_aL.copy() # Grid transformer -- convert array from fine to coarse grid self.restrictor = Transformer(self.finegd, self.gd, nn=3, dtype=self.dtype, allocate=False) # Atom, cartesian coordinate and q-vector of the perturbation self.a = None self.v = None # Local q-vector index of the perturbation if self.kd.gamma: self.q = -1 else: self.q = None
def __init__(self, calc): #initialization self.calc = calc self.wfs = calc.wfs self.ham = calc.hamiltonian self.den = calc.density self.occ = calc.occupations #initialization plane and grid descriptors from GPAW calculation self.pd = calc.wfs.pd self.gd = calc.wfs.gd self.volume = np.abs(np.linalg.det(self.gd.cell_cv)) #number of k-points self.nq = len(calc.wfs.kpt_u) #number of bands self.nbands = calc.get_number_of_bands() #number of electrons self.nelectrons = calc.get_number_of_electrons() #kinetic operator self.kinetic = np.zeros((self.nq, self.nbands, self.nbands), dtype=complex) #overlap operator self.overlap = np.zeros((self.nq, self.nbands, self.nbands), dtype=complex) #local momentum operator self.local_moment = np.zeros((3, self.nq, self.nbands, self.nbands), dtype=complex) #nonlocal momentum operator self.nonlocal_moment = np.zeros((3, self.nq, self.nbands, self.nbands), dtype=complex) #Fermi-Dirac occupation self.f_n = np.zeros((self.nq, self.nbands), dtype=float) #ground state Kohn-Sham orbitals wavefunctions psi_gs = [] #ground state Kohn-Sham orbitals density den_gs = [] for kpt in self.wfs.kpt_u: self.overlap[kpt.q] = np.eye(self.nbands) self.f_n[kpt.q] = kpt.f_n kinetic = 0.5 * self.pd.G2_qG[kpt.q] # |G+q|^2/2 gradient = self.pd.get_reciprocal_vectors(kpt.q) psi = [] den = [] for n in range(self.nbands): psi.append(self.pd.ifft(kpt.psit_nG[n], kpt.q)) den.append(np.abs(psi[-1])**2) for m in range(self.nbands): self.kinetic[kpt.q, n, m] = self.pd.integrate( kpt.psit_nG[n], kinetic * kpt.psit_nG[m]) #calculation local momentum #<psi_qn|\nabla|psi_qm> for i in range(3): self.local_moment[i, kpt.q, n, m] = self.pd.integrate( kpt.psit_nG[n], gradient[:, i] * kpt.psit_nG[m]) psi_gs.append(psi) den_gs.append(den) self.psi_gs = np.array(psi_gs) self.den_gs = np.array(den_gs, dtype=float) #real space grid points self.r = self.gd.get_grid_point_coordinates() #initialization local and nonlocal part of pseudopotential self.init_potential() self.proj = np.zeros((self.nq, self.nbands, self.norb), dtype=complex) self.proj_r = np.zeros((3, self.nq, self.nbands, self.norb), dtype=complex) self.density = self.den.nt_sG.copy() #initialization charge density (ion+electrons) for Hartree potential self.ion_density = calc.hamiltonian.poisson.pd.ifft( calc.density.rhot_q) - calc.density.nt_sg[0] #plane wave descriptor for Hartree potential self.pd0 = self.ham.poisson.pd #reciprocal |G|^2 vectors for Hartree potential V(G)=4pi/|G|^2 self.G2 = self.ham.poisson.G2_q self.G = self.pd0.get_reciprocal_vectors() #fine to coarse and coarse to fine grids transformers (for correct calculation local potential) self.fine_to_coarse = Transformer(calc.density.finegd, calc.density.gd, 3) self.coarse_to_fine = Transformer(calc.density.gd, calc.density.finegd, 3) #initialization local potenital from ground state density self.update_local_potential() self.update_gauge([0, 0, 0])