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 __init__(self, nn=3, relax='J', eps=2e-10, maxiter=1000, moment_corrections=None, extended=None, timer=nulltimer): FDPoissonSolver.__init__(self, nn=nn, relax=relax, eps=eps, maxiter=maxiter, remove_moment=None) self.timer = timer if moment_corrections is None: self.moment_corrections = None elif isinstance(moment_corrections, int): self.moment_corrections = [{'moms': range(moment_corrections), 'center': None}] else: self.moment_corrections = moment_corrections self.is_extended = False # Broadcast over band, kpt, etc. communicators required? self.requires_broadcast = False if extended is not None: self.is_extended = True self.extended = extended assert 'gpts' in extended.keys(), 'gpts parameter is missing' self.extended['gpts'] = np.array(self.extended['gpts']) # Multiply gpts by 2 to get gpts on fine grid self.extended['finegpts'] = self.extended['gpts'] * 2 assert 'useprev' in extended.keys(), 'useprev parameter is missing' if self.extended.get('comm') is not None: self.requires_broadcast = True
def estimate_memory(self, mem): FDPoissonSolver.estimate_memory(self, mem) gdbytes = self.gd.bytecount() if self.is_extended: mem.subnode('extended arrays', 2 * gdbytes) if self.moment_corrections is not None: mem.subnode('moment_corrections masks', len(self.moment_corrections) * gdbytes)
def set_grid_descriptor(self, gd): if self.is_extended: self.gd_original = gd assert np.all(self.gd_original.N_c <= self.extended['finegpts']), \ 'extended grid has to be larger than the original one' gd, _, _ = extended_grid_descriptor( gd, N_c=self.extended['finegpts'], extcomm=self.extended.get('comm')) FDPoissonSolver.set_grid_descriptor(self, gd)
def __init__(self, k2=0.0, nn='M', relax='GS', eps=2e-10, use_charge_center=True): assert k2 <= 0, 'Currently only defined for k^2<=0' FDPoissonSolver.__init__(self, nn, relax, eps, use_charge_center=use_charge_center) self.k2 = k2
def initialize(self, load_gauss=False): FDPoissonSolver.initialize(self, load_gauss=load_gauss) if self.is_extended: if not self.gd.orthogonal or self.gd.pbc_c.any(): raise NotImplementedError('Only orthogonal unit cells' + 'and non-periodic boundary' + 'conditions are tested') self.rho_g = self.gd.zeros() self.phi_g = self.gd.zeros() if self.moment_corrections is not None: if not self.gd.orthogonal or self.gd.pbc_c.any(): raise NotImplementedError('Only orthogonal unit cells' + 'and non-periodic boundary' + 'conditions are tested') self.load_moment_corrections_gauss()
def __init__(self, nn=3, relax='J', eps=2e-10, maxiter=1000, remove_moment=None, use_charge_center=True): if remove_moment is not None: raise NotImplementedError( 'Removing arbitrary multipole moments ' 'is not implemented for SolvationPoissonSolver!') FDPoissonSolver.__init__(self, nn, relax, eps, maxiter, remove_moment, use_charge_center=use_charge_center)
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 get_description(self): description = FDPoissonSolver.get_description(self) lines = [description] if self.is_extended: lines.extend([' Extended %d*%d*%d grid' % tuple(self.gd.N_c)]) lines.extend([' Use previous is %s' % self.extended['useprev']]) if self.moment_corrections: lines.extend( [' %d moment corrections:' % len(self.moment_corrections)]) lines.extend([ ' %s' % ('[%s] %s' % ('center' if mom['center'] is None else (', '.join(['%.2f' % (x * Bohr) for x in mom['center']])), mom['moms'])) for mom in self.moment_corrections ]) return '\n'.join(lines)
import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.lrtddft import LrTDDFT from gpaw.inducedfield.inducedfield_lrtddft import LrTDDFTInducedField from gpaw.poisson import FDPoissonSolver from gpaw.test import equal do_print_values = False # Use this for printing the reference values poisson_eps = 1e-12 density_eps = 1e-6 # 0) PoissonSolver poissonsolver = FDPoissonSolver(eps=poisson_eps) # 1) Ground state calculation with empty states atoms = Atoms(symbols='Na2', positions=[(0, 0, 0), (3.0, 0, 0)], pbc=False) atoms.center(vacuum=3.0) calc = GPAW(nbands=20, h=0.6, setups={'Na': '1'}, poissonsolver=poissonsolver, experimental={'niter_fixdensity': 2}, convergence={'density': density_eps}) atoms.set_calculator(calc) energy = atoms.get_potential_energy() calc.write('na2_gs_casida.gpw', mode='all') # 2) Casida calculation calc = GPAW('na2_gs_casida.gpw')
def load_gauss(self, center=None): return FDPoissonSolver.load_gauss(self, center=center)
from gpaw.poisson import NonPeriodicLauePoissonSolver, GeneralizedLauePoissonSolver, FDPoissonSolver, idst2, dst2 from gpaw.grid_descriptor import GridDescriptor import numpy as np 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)
from __future__ import print_function import numpy as np from ase.build import molecule from gpaw import GPAW from gpaw.poisson import FDPoissonSolver from gpaw.lcao.projected_wannier import get_lcao_projections_HSP atoms = molecule('C2H2') atoms.center(vacuum=3.0) calc = GPAW(gpts=(32, 32, 48), experimental={'niter_fixdensity': 2}, poissonsolver=FDPoissonSolver(), eigensolver='rmm-diis') atoms.set_calculator(calc) atoms.get_potential_energy() V_qnM, H_qMM, S_qMM, P_aqMi = get_lcao_projections_HSP(calc, bfs=None, spin=0, projectionsonly=False) # Test H and S eig = sorted(np.linalg.eigvals(np.linalg.solve(S_qMM[0], H_qMM[0])).real) eig_ref = np.array([ -17.879390089021275, -13.248786165187855, -11.431259875271436, -7.125783046831621, -7.125783046831554, 0.5927193710189584, 0.5927193710191426, 3.9251078324544673, 7.450995963662965, 26.734277387029234 ]) print(eig)
p.set_grid_descriptor(gd) cut = N / 2.0 * 0.9 s = Spline(l=0, rmax=cut, f_g=np.array([1, 0.5, 0.0])) c = LFC(gd, [[s], [s]]) c.set_positions([(0, 0, 0), (0.5, 0.5, 0.5)]) c.add(a) I0 = gd.integrate(a) a -= I0 / L**3 b = gd.zeros() p.solve(b, a, charge=0, eps=1e-20) return gd.collect(b, broadcast=1) b1 = f(8, FDPoissonSolver(nn=1, relax='J')) b2 = f(8, FDPoissonSolver(nn=1, relax='GS')) b3 = f(8, PoissonSolver(nn=1)) err1 = abs(b1[0, 0, 0] - b1[8, 8, 8]) err2 = abs(b2[0, 0, 0] - b2[8, 8, 8]) err3 = abs(b1[0, 0, 0] - b3[8, 8, 8]) print(err1) print(err2) print(err3) assert err3 < 1e-10 assert err1 < 6e-16 assert err2 < 3e-6 # XXX Shouldn't this be better? b4 = f(8, FFTPoissonSolver()) err4 = abs(b4[0, 0, 0] - b4[8, 8, 8]) print(err4)
from gpaw.test import equal, gen # Generate setup for oxygen with half a core-hole: gen('O', name='hch1s', corehole=(1, 0, 0.5)) a = 5.0 d = 0.9575 t = pi / 180 * 104.51 H2O = Atoms([Atom('O', (0, 0, 0)), Atom('H', (d, 0, 0)), Atom('H', (d * cos(t), d * sin(t), 0))], cell=(a, a, a), pbc=False) H2O.center() calc = GPAW(nbands=10, h=0.2, setups={'O': 'hch1s'}, experimental={'niter_fixdensity': 2}, poissonsolver=FDPoissonSolver(use_charge_center=True)) H2O.set_calculator(calc) e = H2O.get_potential_energy() niter = calc.get_number_of_iterations() import gpaw.mpi as mpi if mpi.size == 1: xas = XAS(calc) x, y = xas.get_spectra() e1_n = xas.eps_n de1 = e1_n[1] - e1_n[0] calc.write('h2o-xas.gpw') if mpi.size == 1:
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
def poisson_solve(gd, rho_g, poisson): phi_g = gd.zeros() npoisson = poisson.solve(phi_g, rho_g) return phi_g, npoisson def compare(phi1_g, phi2_g, val): big_phi1_g = gd.collect(phi1_g) big_phi2_g = gd.collect(phi2_g) if gd.comm.rank == 0: equal(np.max(np.absolute(big_phi1_g - big_phi2_g)), val, np.sqrt(poissoneps)) # Get reference from default poissonsolver poisson = PoissonSolver(eps=poissoneps) poisson.set_grid_descriptor(gd) phiref_g, npoisson = poisson_solve(gd, rho_g, poisson) # Test agreement with default poisson = ExtendedPoissonSolver(eps=poissoneps) poisson.set_grid_descriptor(gd) phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g) compare(phi_g, phiref_g, 0.0) # Test moment_corrections=int poisson = ExtendedPoissonSolver(eps=poissoneps, moment_corrections=4) poisson.set_grid_descriptor(gd) phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g)