def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): if self.phi_tilde is None: self.phi_tilde = self.gd.zeros() phi_tilde = self.phi_tilde niter_tilde = FDPoissonSolver.solve(self, phi_tilde, rho, None, self.eps, maxcharge, False) epsr, dx_epsr, dy_epsr, dz_epsr = self.dielectric.eps_gradeps dx_phi_tilde = self.gd.empty() dy_phi_tilde = self.gd.empty() dz_phi_tilde = self.gd.empty() Gradient(self.gd, 0, 1.0, self.nn).apply(phi_tilde, dx_phi_tilde) Gradient(self.gd, 1, 1.0, self.nn).apply(phi_tilde, dy_phi_tilde) Gradient(self.gd, 2, 1.0, self.nn).apply(phi_tilde, dz_phi_tilde) scalar_product = (dx_epsr * dx_phi_tilde + dy_epsr * dy_phi_tilde + dz_epsr * dz_phi_tilde) rho_and_pol = (rho / epsr + scalar_product / (4. * np.pi * epsr**2)) niter = FDPoissonSolver.solve(self, phi, rho_and_pol, None, eps, maxcharge, zero_initial_phi) return niter_tilde + niter
def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): if self.gd.pbc_c.all(): actual_charge = self.gd.integrate(rho) if abs(actual_charge) > maxcharge: raise NotImplementedError( 'charged periodic systems are not implemented') return FDPoissonSolver.solve(self, phi, rho, charge, eps, maxcharge, zero_initial_phi)
def _solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): self._init() if eps is None: eps = self.eps if self.moment_corrections: assert not self.gd.pbc_c.any() self.timer.start('Multipole moment corrections') rho_neutral = rho * 0.0 phi_cor_k = [] for gauss, mask_g, mom_j in zip(self.gauss_i, self.mask_ig, self.mom_ij): rho_masked = rho * mask_g for mom in mom_j: phi_cor_k.append(gauss.remove_moment(rho_masked, mom)) rho_neutral += rho_masked # Remove multipoles for better initial guess for phi_cor in phi_cor_k: phi -= phi_cor self.timer.stop('Multipole moment corrections') self.timer.start('Solve neutral') niter = self.solve_neutral(phi, rho_neutral, eps=eps) self.timer.stop('Solve neutral') self.timer.start('Multipole moment corrections') # correct error introduced by removing multipoles for phi_cor in phi_cor_k: phi += phi_cor self.timer.stop('Multipole moment corrections') return niter else: return FDPoissonSolver.solve(self, phi, rho, charge, eps, maxcharge, zero_initial_phi)
def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False, timer=None): self._init() if self.gd.pbc_c.all(): actual_charge = self.gd.integrate(rho) if abs(actual_charge) > maxcharge: raise NotImplementedError( 'charged periodic systems are not implemented') self.restrict_op_weights() ret = FDPoissonSolver.solve(self, phi, rho, charge, eps, maxcharge, zero_initial_phi) return ret
def test(cellno, cellname, cell_cv, idiv, pbc, nn): N_c = h2gpts(0.12, cell_cv, idiv=idiv) if idiv == 1: N_c += 1 - N_c % 2 # We want especially to test uneven grids gd = GridDescriptor(N_c, cell_cv, pbc_c=pbc) rho_g = gd.zeros() phi_g = gd.zeros() rho_g[:] = -0.3 + rng.rand(*rho_g.shape) # Neutralize charge: charge = gd.integrate(rho_g) magic = gd.get_size_of_global_array().prod() rho_g -= charge / gd.dv / magic charge = gd.integrate(rho_g) assert abs(charge) < 1e-12 # Check use_cholesky=True/False ? from gpaw.poisson import FDPoissonSolver ps = FastPoissonSolver(nn=nn) #print('setgrid') # Will raise BadAxesError for some pbc/cell combinations ps.set_grid_descriptor(gd) ps.solve(phi_g, rho_g) laplace = Laplace(gd, scale=-1.0 / (4.0 * np.pi), n=nn) def get_residual_err(phi_g): rhotest_g = gd.zeros() laplace.apply(phi_g, rhotest_g) residual = np.abs(rhotest_g - rho_g) # Residual is not accurate at end of non-periodic directions # except for nn=1 (since effectively we use the right stencil # only for nn=1 at the boundary). # # To do this check correctly, the Laplacian should have lower # nn at the boundaries. Therefore we do not test the residual # at these ends, only in between, by zeroing the bad ones: if nn > 1: exclude_points = nn - 1 for c in range(3): if nn > 1 and not pbc[c]: # get view ehere axis c refers becomes zeroth dimension: X = residual.transpose(c, (c + 1) % 3, (c + 2) % 3) if gd.beg_c[c] == 1: X[:exclude_points] = 0.0 if gd.end_c[c] == gd.N_c[c]: X[-exclude_points:] = 0.0 return residual.max() maxerr = get_residual_err(phi_g) pbcstring = '{}{}{}'.format(*pbc) if 0: ps2 = FDPoissonSolver(relax='J', nn=nn, eps=1e-18) ps2.set_grid_descriptor(gd) phi2_g = gd.zeros() ps2.solve(phi2_g, rho_g) phimaxerr = np.abs(phi2_g - phi_g).max() maxerr2 = get_residual_err(phi2_g) msg = ('{:2d} {:8s} pbc={} err={:8.5e} err[J]={:8.5e} ' 'err[phi]={:8.5e} nn={:1d}' .format(cellno, cellname, pbcstring, maxerr, maxerr2, phimaxerr, nn)) state = 'ok' if maxerr < tolerance else 'FAIL' msg = ('{:2d} {:8s} grid={} pbc={} err[fast]={:8.5e} nn={:1d} {}' .format(cellno, cellname, N_c, pbcstring, maxerr, nn, state)) if world.rank == 0: print(msg) return maxerr
gd = GridDescriptor((10,12,42), (4, 5, 20), pbc_c=(True,True,False)) poisson = GeneralizedLauePoissonSolver(nn=2) poisson.set_grid_descriptor(gd) poisson2 = FDPoissonSolver(nn=2, eps=1e-28) poisson2.set_grid_descriptor(gd) phi_g = gd.zeros() phi2_g = gd.zeros() rho_g = gd.zeros() rho_g[4,5,6] = 1.0 rho_g[4,5,7] = -1.0 poisson.solve(phi_g, rho_g) poisson2.solve(phi2_g, rho_g) print("this", phi_g[4,5,:]) print("ref", phi2_g[4,5,:]) print("diff", phi_g[4,5,:]-phi2_g[4,5,:]) assert np.linalg.norm(phi_g-phi2_g) < 1e-10 gd = GridDescriptor((10,12,42), (10, 12, 42), pbc_c=(False,False,False)) poisson = NonPeriodicLauePoissonSolver(nn=1) poisson.set_grid_descriptor(gd) print("eigs", poisson.eigs_c[0]) poisson2 = FDPoissonSolver(nn=1, eps=1e-24) poisson2.set_grid_descriptor(gd) phi_g = gd.zeros() phi2_g = gd.zeros()