예제 #1
0
    def initialize(self, density, hamiltonian, wfs, occ=None):
        assert wfs.kd.gamma
        assert not wfs.gd.pbc_c.any()
        assert wfs.bd.comm.size == 1  # band parallelization unsupported

        self.wfs = wfs
        self.dtype = float
        self.xc.initialize(density, hamiltonian, wfs, occ)
        self.kpt_comm = wfs.kd.comm
        self.nspins = wfs.nspins
        self.nbands = wfs.bd.nbands

        self.finegd = density.gd.refine() if self.finegrid else density.gd
        self.ghat = LFC(self.finegd,
                        [setup.ghat_l for setup in density.setups],
                        integral=np.sqrt(4 * np.pi),
                        forces=True)

        poissonsolver = PoissonSolver(eps=1e-14)
        poissonsolver.set_grid_descriptor(self.finegd)

        self.spin_s = {}
        for kpt in wfs.kpt_u:
            self.spin_s[kpt.s] = SICSpin(kpt, self.xc, density, hamiltonian,
                                         wfs, poissonsolver, self.ghat,
                                         self.finegd, **self.parameters)
예제 #2
0
파일: coulomb.py 프로젝트: thonmaker/gpaw
    def load(self, method):
        """Make sure all necessary attributes have been initialized"""

        assert method in ('real', 'recip_gauss', 'recip_ewald'),\
            str(method) + ' is an invalid method name,\n' +\
            'use either real, recip_gauss, or recip_ewald'

        if method.startswith('recip'):
            if self.gd.comm.size > 1:
                raise RuntimeError("Cannot do parallel FFT, use method='real'")
            if not hasattr(self, 'k2'):
                self.k2, self.N3 = construct_reciprocal(self.gd)
            if method.endswith('ewald') and not hasattr(self, 'ewald'):
                # cutoff radius
                assert self.gd.orthogonal
                rc = 0.5 * np.average(self.gd.cell_cv.diagonal())
                # ewald potential: 1 - cos(k rc)
                self.ewald = (np.ones(self.gd.n_c) -
                              np.cos(np.sqrt(self.k2) * rc))
                # lim k -> 0 ewald / k2
                self.ewald[0, 0, 0] = 0.5 * rc**2
            elif method.endswith('gauss') and not hasattr(self, 'ng'):
                gauss = Gaussian(self.gd)
                self.ng = gauss.get_gauss(0) / sqrt(4 * pi)
                self.vg = gauss.get_gauss_pot(0) / sqrt(4 * pi)
        else:  # method == 'real'
            if not hasattr(self, 'solve'):
                if self.poisson is not None:
                    self.solve = self.poisson.solve
                else:
                    solver = PoissonSolver('fd', nn=2)
                    solver.set_grid_descriptor(self.gd)
                    #solver.initialize()
                    self.solve = solver.solve
예제 #3
0
    def load(self, method):
        """Make sure all necessary attributes have been initialized"""

        assert method in ('real', 'recip_gauss', 'recip_ewald'),\
            str(method) + ' is an invalid method name,\n' +\
            'use either real, recip_gauss, or recip_ewald'

        if method.startswith('recip'):
            if self.gd.comm.size > 1:
                raise RuntimeError("Cannot do parallel FFT, use method='real'")
            if not hasattr(self, 'k2'):
                self.k2, self.N3 = construct_reciprocal(self.gd)
            if method.endswith('ewald') and not hasattr(self, 'ewald'):
                # cutoff radius
                assert self.gd.orthogonal
                rc = 0.5 * np.average(self.gd.cell_cv.diagonal())
                # ewald potential: 1 - cos(k rc)
                self.ewald = (np.ones(self.gd.n_c) -
                              np.cos(np.sqrt(self.k2) * rc))
                # lim k -> 0 ewald / k2
                self.ewald[0, 0, 0] = 0.5 * rc**2
            elif method.endswith('gauss') and not hasattr(self, 'ng'):
                gauss = Gaussian(self.gd)
                self.ng = gauss.get_gauss(0) / sqrt(4 * pi)
                self.vg = gauss.get_gauss_pot(0) / sqrt(4 * pi)
        else:  # method == 'real'
            if not hasattr(self, 'solve'):
                if self.poisson is not None:
                    self.solve = self.poisson.solve
                else:
                    solver = PoissonSolver(nn=2)
                    solver.set_grid_descriptor(self.gd)
                    solver.initialize(load_gauss=True)
                    self.solve = solver.solve
예제 #4
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)

        if self.finegrid:
            self.poissonsolver = hamiltonian.poisson
            self.ghat = density.ghat
            self.interpolator = density.interpolator
            self.restrictor = hamiltonian.restrictor
        else:
            self.poissonsolver = PoissonSolver(eps=1e-11)
            self.poissonsolver.set_grid_descriptor(density.gd)
            self.poissonsolver.initialize()
            self.ghat = LFC(density.gd,
                            [setup.ghat_l for setup in density.setups],
                            integral=np.sqrt(4 * np.pi),
                            forces=True)
        self.gd = density.gd
        self.finegd = self.ghat.gd
예제 #5
0
파일: sic.py 프로젝트: eojons/gpaw-scme
    def initialize(self, density, hamiltonian, wfs, occ=None):
        
        assert wfs.gamma
        assert not wfs.gd.pbc_c.any()

        self.wfs = wfs
        self.dtype = float
        self.xc.initialize(density, hamiltonian, wfs, occ)
        self.kpt_comm = wfs.kpt_comm
        self.nspins = wfs.nspins
        self.nbands = wfs.bd.nbands
        
        if self.finegrid:
            self.finegd = density.finegd
            self.ghat = density.ghat
        else:
            self.finegd = density.gd
            self.ghat = LFC(self.finegd,
                        [setup.ghat_l for setup in density.setups],
                        integral=sqrt(4 * pi), forces=True)
        
        poissonsolver = PoissonSolver(eps=1e-14)
        poissonsolver.set_grid_descriptor(self.finegd)
        poissonsolver.initialize()
        
        self.spin_s = {}
        for kpt in wfs.kpt_u:
            self.spin_s[kpt.s] = SICSpin(kpt, self.xc,
                                         density, hamiltonian, wfs,
                                         poissonsolver, self.ghat,
                                         self.finegd, **self.parameters)
예제 #6
0
def calculate_field(
        gd,
        rho_g,
        bgef_v,
        phi_g,
        ef_vg,
        fe_g,  # preallocated numpy arrays
        nv=3,
        poisson_nn=3,
        poisson_relax='J',
        gradient_n=3,
        poisson_eps=1e-20):

    dtype = rho_g.dtype
    yes_complex = dtype == complex

    phi_g[:] = 0.0
    ef_vg[:] = 0.0
    fe_g[:] = 0.0
    tmp_g = gd.zeros(dtype=float)

    # Poissonsolver
    poissonsolver = PoissonSolver(nn=poisson_nn,
                                  relax=poisson_relax,
                                  eps=poisson_eps)
    poissonsolver.set_grid_descriptor(gd)
    poissonsolver.initialize()

    # Potential, real part
    poissonsolver.solve(tmp_g, rho_g.real.copy())
    phi_g += tmp_g
    # Potential, imag part
    if yes_complex:
        tmp_g[:] = 0.0
        poissonsolver.solve(tmp_g, rho_g.imag.copy())
        phi_g += 1.0j * tmp_g

    # Gradient
    gradient = [Gradient(gd, v, scale=1.0, n=gradient_n) for v in range(nv)]
    for v in range(nv):
        # Electric field, real part
        gradient[v].apply(-phi_g.real, tmp_g)
        ef_vg[v] += tmp_g
        # Electric field, imag part
        if yes_complex:
            gradient[v].apply(-phi_g.imag, tmp_g)
            ef_vg[v] += 1.0j * tmp_g

    # Electric field enhancement
    tmp_g[:] = 0.0  # total electric field norm
    bgefnorm = 0.0  # background electric field norm
    for v in range(nv):
        tmp_g += np.absolute(bgef_v[v] + ef_vg[v])**2
        bgefnorm += np.absolute(bgef_v[v])**2

    tmp_g = np.sqrt(tmp_g)
    bgefnorm = np.sqrt(bgefnorm)

    fe_g[:] = tmp_g / bgefnorm
예제 #7
0
    def __init__(self, z1, z2, **kwargs):
        """Put the positive background charge where z1 < z < z2.

        z1: float
            Position of lower surface in Angstrom units.
        z2: float
            Position of upper surface in Angstrom units."""
        
        PoissonSolver.__init__(self, **kwargs)
        self.z1 = (z1 - 0.0001)  / Bohr
        self.z2 = (z2 - 0.0001) / Bohr
예제 #8
0
    def solve(self):
        hamiltonian = self.calculator.hamiltonian
        self.poisson = PoissonSolver('fd', nn=hamiltonian.poisson.nn)
        self.poisson.set_grid_descriptor(self.gd)
        self.poisson.initialize()

        corrt_G = self.gd.empty()
        self.poisson.solve(corrt_G, self.vt_G, charge=None)
        corrt_G /= (2 * pi)**(5. / 2)

        self.corrt_G = corrt_G
예제 #9
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

        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)
예제 #10
0
파일: coulomb.py 프로젝트: thonmaker/gpaw
class CoulombNEW:
    def __init__(self, gd, setups, spos_ac, fft=False):
        assert gd.comm.size == 1
        self.rhot1_G = gd.empty()
        self.rhot2_G = gd.empty()
        self.pot_G = gd.empty()
        self.dv = gd.dv
        if fft:
            self.poisson = FFTPoissonSolver()
        else:
            self.poisson = PoissonSolver(name='fd', nn=3)
        self.poisson.set_grid_descriptor(gd)
        self.setups = setups

        # Set coarse ghat
        self.Ghat = LFC(gd, [setup.ghat_l for setup in setups],
                        integral=sqrt(4 * pi))
        self.Ghat.set_positions(spos_ac)

    def calculate(self, nt1_G, nt2_G, P1_ap, P2_ap):
        I = 0.0
        self.rhot1_G[:] = nt1_G
        self.rhot2_G[:] = nt2_G

        Q1_aL = {}
        Q2_aL = {}
        for a, P1_p in P1_ap.items():
            P2_p = P2_ap[a]
            setup = self.setups[a]

            # Add atomic corrections to integral
            I += 2 * np.dot(P1_p, np.dot(setup.M_pp, P2_p))

            # Add compensation charges to pseudo densities
            Q1_aL[a] = np.dot(P1_p, setup.Delta_pL)
            Q2_aL[a] = np.dot(P2_p, setup.Delta_pL)
        self.Ghat.add(self.rhot1_G, Q1_aL)
        self.Ghat.add(self.rhot2_G, Q2_aL)

        # Add coulomb energy of compensated pseudo densities to integral
        self.poisson.solve(self.pot_G,
                           self.rhot2_G,
                           charge=None,
                           eps=1e-12,
                           zero_initial_phi=True)
        I += np.vdot(self.rhot1_G, self.pot_G) * self.dv

        return I * Hartree
예제 #11
0
    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
예제 #12
0
파일: hybrid.py 프로젝트: robwarm/gpaw-symm
 def initialize(self, density, hamiltonian, wfs, occupations):
     assert wfs.gamma
     self.xc.initialize(density, hamiltonian, wfs, occupations)
     self.kpt_comm = wfs.kpt_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)
     
     if self.finegrid:
         self.poissonsolver = hamiltonian.poisson
         self.ghat = density.ghat
         self.interpolator = density.interpolator
         self.restrictor = hamiltonian.restrictor
     else:
         self.poissonsolver = PoissonSolver(eps=1e-11)
         self.poissonsolver.set_grid_descriptor(density.gd)
         self.poissonsolver.initialize()
         self.ghat = LFC(density.gd,
                         [setup.ghat_l for setup in density.setups],
                         integral=np.sqrt(4 * np.pi), forces=True)
     self.gd = density.gd
     self.finegd = self.ghat.gd
예제 #13
0
파일: coulomb.py 프로젝트: thonmaker/gpaw
    def __init__(self, gd, setups, spos_ac, fft=False):
        assert gd.comm.size == 1
        self.rhot1_G = gd.empty()
        self.rhot2_G = gd.empty()
        self.pot_G = gd.empty()
        self.dv = gd.dv
        if fft:
            self.poisson = FFTPoissonSolver()
        else:
            self.poisson = PoissonSolver(name='fd', nn=3)
        self.poisson.set_grid_descriptor(gd)
        self.setups = setups

        # Set coarse ghat
        self.Ghat = LFC(gd, [setup.ghat_l for setup in setups],
                        integral=sqrt(4 * pi))
        self.Ghat.set_positions(spos_ac)
예제 #14
0
def prepare(setups):
    calc = GPAW(basis={'H' : b}, mode='lcao',
                setups=setups, h=0.2,
                poissonsolver=PoissonSolver('M', relax='GS', eps=1e-5),
                spinpol=False,
                nbands=1)
    system.set_calculator(calc)
    return calc
예제 #15
0
def get_calculator():
    calc = GPAW(h=0.2,
                mode = 'lcao',
                basis = 'szp(dzp)',
                mixer=Mixer(beta=0.1, nmaxold=5, weight=50.0),
                poissonsolver=PoissonSolver(nn='M', relax='GS'),
                txt='C5H12.txt')
    return calc
예제 #16
0
    def __init__(self, gd, setups, spos_ac, fft=False):
        assert gd.comm.size == 1
        self.rhot1_G = gd.empty()
        self.rhot2_G = gd.empty()
        self.pot_G = gd.empty()
        self.dv = gd.dv
        if fft:
            self.poisson = FFTPoissonSolver()
        else:
            self.poisson = PoissonSolver(nn=3)
        self.poisson.set_grid_descriptor(gd)
        self.poisson.initialize()
        self.setups = setups

        # Set coarse ghat
        self.Ghat = LFC(gd, [setup.ghat_l for setup in setups],
                        integral=sqrt(4 * pi))
        self.Ghat.set_positions(spos_ac)
예제 #17
0
    def solve(self):
        hamiltonian = self.calculator.hamiltonian
        self.poisson = PoissonSolver(nn=hamiltonian.poisson.nn)
        self.poisson.set_grid_descriptor(self.gd)
        self.poisson.initialize()

        corrt_G = self.gd.empty()
        self.poisson.solve(corrt_G, self.vt_G, charge=None)
        corrt_G /= (2 * pi)**(5. / 2)

        self.corrt_G = corrt_G
예제 #18
0
파일: sic.py 프로젝트: yihsuanliu/gpaw
    def initialize(self, density, hamiltonian, wfs, occ=None):

        assert wfs.gamma

        self.wfs = wfs
        self.dtype = float
        self.xc.initialize(density, hamiltonian, wfs, occ)
        self.kpt_comm = wfs.kpt_comm
        self.nspins = wfs.nspins
        self.nbands = wfs.nbands

        if self.finegrid:
            self.finegd = density.finegd
            self.ghat = density.ghat
        else:
            self.finegd = density.gd
            self.ghat = LFC(self.finegd,
                            [setup.ghat_l for setup in density.setups],
                            integral=sqrt(4 * pi),
                            forces=True)

        poissonsolver = PoissonSolver(eps=1e-14)
        poissonsolver.set_grid_descriptor(self.finegd)
        poissonsolver.initialize()

        self.spin_s = {}
        for kpt in wfs.kpt_u:
            self.spin_s[kpt.s] = SICSpin(kpt, self.xc, density, hamiltonian,
                                         wfs, poissonsolver, self.ghat,
                                         self.finegd, **self.parameters)
예제 #19
0
def get_calculator():
    calc = GPAW(gpts=(64, 64, 64), #h=0.18, gives 64x60x60
                mode='lcao', 
                basis='szp(dzp)',
                nbands=-5,
                xc='LDA',
                width=0.1,
                mixer=Mixer(beta=0.1, nmaxold=5, weight=50.0),
                poissonsolver=PoissonSolver(nn='M', relax='GS'),
                convergence={'energy': 1e-4, 'bands': -3},
                stencils=(3, 3),
                txt='nanoparticle.txt')
    return calc
예제 #20
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()
예제 #21
0
def get_calculator():
    basis = 'szp(dzp)'
    calc = GPAW(
        gpts=(64, 64, 128),  # ca h=0.25
        width=0.1,
        nbands=-5,
        xc='LDA',
        mode='lcao',
        txt='C2_Cu100.txt',
        mixer=Mixer(beta=0.1, nmaxold=5, weight=50.0),
        poissonsolver=PoissonSolver(nn='M', relax='GS'),
        stencils=(3, 3),
        maxiter=400,
        basis=basis)
    return calc
예제 #22
0
    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 calc_eng_homo_lumo(atoms):

    # set gpaw calculator
    calc = GPAW(
        h=0.16,
        kpts=(1, 1, 1),
        xc='B3LYP',
        occupations=FermiDirac(width=0.1),
        # eigensolver=Davidson(3),
        eigensolver=RMMDIIS(),
        poissonsolver=PoissonSolver(eps=1e-12),
        maxiter=2000)

    atoms.calc = calc
    energy = atoms.get_potential_energy()
    print(energy)
    (h**o, lumo) = calc.get_homo_lumo()
    print("h**o: {} and LUMO: {}".format(h**o, lumo))
    return h**o, lumo
예제 #24
0
class ZerothOrder1(State):

    def __init__(self, calculator):
        self.calculator = calculator
        State.__init__(self, calculator.gd)
        self.pw = PlaneWave(self.gd)

        # get effective potential
        hamiltonian = self.calculator.hamiltonian
        if 1:
            self.vt_G = hamiltonian.vt_sG[0]  # XXX treat spin
        else:
            self.vt_G = np.where(hamiltonian.vt_sG[0] > 0,
                                 0.0, hamiltonian.vt_sG[0])
        self.intvt = self.gd.integrate(self.vt_G)
        print('# int(vt_G)=', self.intvt, np.sometrue(self.vt_G > 0))

        self.solve()

    def get_grid(self, k_c, r0):
        print('Correction:', self.gd.integrate(self.corrt_G))
        if not hasattr(self, 'written'):
            print('r0', r0, r0 * Bohr)
            dR = 0.3
            AI = AngularIntegral(r0 * Bohr, self.gd, dR=dR)
            r_R = AI.radii()
            psi_R = AI.average(self.corrt_G)
            v_R = AI.average(self.vt_G)
            f = open('radial_dR' + str(dR) + '.dat', 'w')
            print('# R  v(R)    psi(R)', file=f)
            for r, psi, v in zip(r_R, psi_R, v_R):
                print(r, psi, v, file=f)
            f.close()
            self.written = True

        return self.pw.get_grid(k_c, r0) - 1e6 * self.corrt_G

    def solve(self):
        hamiltonian = self.calculator.hamiltonian
        self.poisson = PoissonSolver(nn=hamiltonian.poisson.nn)
        self.poisson.set_grid_descriptor(self.gd)
        self.poisson.initialize()

        corrt_G = self.gd.empty()
        self.poisson.solve(corrt_G, self.vt_G, charge=None)
        corrt_G /= (2 * pi) ** (5. / 2)

        self.corrt_G = corrt_G
예제 #25
0
class ZerothOrder1(State):
    def __init__(self, calculator):
        self.calculator = calculator
        State.__init__(self, calculator.gd)
        self.pw = PlaneWave(self.gd)

        # get effective potential
        hamiltonian = self.calculator.hamiltonian
        if 1:
            self.vt_G = hamiltonian.vt_sG[0]  # XXX treat spin
        else:
            self.vt_G = np.where(hamiltonian.vt_sG[0] > 0, 0.0,
                                 hamiltonian.vt_sG[0])
        self.intvt = self.gd.integrate(self.vt_G)
        print('# int(vt_G)=', self.intvt, np.sometrue(self.vt_G > 0))

        self.solve()

    def get_grid(self, k_c, r0):
        print('Correction:', self.gd.integrate(self.corrt_G))
        if not hasattr(self, 'written'):
            print('r0', r0, r0 * Bohr)
            dR = 0.3
            AI = AngularIntegral(r0 * Bohr, self.gd, dR=dR)
            r_R = AI.radii()
            psi_R = AI.average(self.corrt_G)
            v_R = AI.average(self.vt_G)
            f = open('radial_dR' + str(dR) + '.dat', 'w')
            print('# R  v(R)    psi(R)', file=f)
            for r, psi, v in zip(r_R, psi_R, v_R):
                print(r, psi, v, file=f)
            f.close()
            self.written = True

        return self.pw.get_grid(k_c, r0) - 1e6 * self.corrt_G

    def solve(self):
        hamiltonian = self.calculator.hamiltonian
        self.poisson = PoissonSolver('fd', nn=hamiltonian.poisson.nn)
        self.poisson.set_grid_descriptor(self.gd)
        self.poisson.initialize()

        corrt_G = self.gd.empty()
        self.poisson.solve(corrt_G, self.vt_G, charge=None)
        corrt_G /= (2 * pi)**(5. / 2)

        self.corrt_G = corrt_G
예제 #26
0
class CoulombNEW:
    def __init__(self, gd, setups, spos_ac, fft=False):
        assert gd.comm.size == 1
        self.rhot1_G = gd.empty()
        self.rhot2_G = gd.empty()
        self.pot_G = gd.empty()
        self.dv = gd.dv
        if fft:
            self.poisson = FFTPoissonSolver()
        else:
            self.poisson = PoissonSolver(nn=3)
        self.poisson.set_grid_descriptor(gd)
        self.poisson.initialize()
        self.setups = setups

        # Set coarse ghat
        self.Ghat = LFC(gd, [setup.ghat_l for setup in setups],
                        integral=sqrt(4 * pi))
        self.Ghat.set_positions(spos_ac)

    def calculate(self, nt1_G, nt2_G, P1_ap, P2_ap):
        I = 0.0
        self.rhot1_G[:] = nt1_G
        self.rhot2_G[:] = nt2_G

        Q1_aL = {}
        Q2_aL = {}
        for a, P1_p in P1_ap.items():
            P2_p = P2_ap[a]
            setup = self.setups[a]

            # Add atomic corrections to integral
            I += 2 * np.dot(P1_p, np.dot(setup.M_pp, P2_p))

            # Add compensation charges to pseudo densities
            Q1_aL[a] = np.dot(P1_p, setup.Delta_pL)
            Q2_aL[a] = np.dot(P2_p, setup.Delta_pL)
        self.Ghat.add(self.rhot1_G, Q1_aL)
        self.Ghat.add(self.rhot2_G, Q2_aL)

        # Add coulomb energy of compensated pseudo densities to integral
        self.poisson.solve(self.pot_G, self.rhot2_G, charge=None,
                           eps=1e-12, zero_initial_phi=True)
        I += np.vdot(self.rhot1_G, self.pot_G) * self.dv

        return I * Hartree
예제 #27
0
basis = BasisMaker('Na').generate(1, 1, energysplit=0.3)

atoms = Atoms('Na12', pbc=(1, 1, 1), cell=[L, L, 12 * a])
atoms.positions[:12, 2] = [i * a for i in range(12)]
atoms.positions[:, :2] = L / 2.
atoms.center()
pl_atoms1 = range(4)
pl_atoms2 = range(8, 12)
pl_cell1 = (L, L, 4 * a)
pl_cell2 = pl_cell1

t = Transport(h=0.3,
              xc='LDA',
              basis={'Na': basis},
              kpts=(2, 2, 1),
              occupations=FermiDirac(0.1),
              mode='lcao',
              poissonsolver=PoissonSolver(nn=2, relax='GS'),
              txt='Na_lcao.txt',
              mixer=Mixer(0.1, 5, weight=100.0),
              guess_steps=10,
              pl_atoms=[pl_atoms1, pl_atoms2],
              pl_cells=[pl_cell1, pl_cell2],
              pl_kpts=(2, 2, 15),
              analysis_data_list=['tc'],
              edge_atoms=[[0, 3], [0, 11]],
              mol_atoms=range(4, 8))
atoms.set_calculator(t)
t.calculate_iv(0.5, 2)
예제 #28
0
파일: hybrid.py 프로젝트: robwarm/gpaw-symm
class HybridXC(HybridXCBase):
    def __init__(self, name, hybrid=None, xc=None, 
                 finegrid=False, unocc=False):
        """Mix standard functionals with exact exchange.

        finegrid: boolean
            Use fine grid for energy functional evaluations ?
        unocc: boolean
            Apply vxx also to unoccupied states ?
        """
        self.finegrid = finegrid
        self.unocc = unocc
        HybridXCBase.__init__(self, name, hybrid, xc)
        
    def calculate_paw_correction(self, setup, D_sp, dEdD_sp=None,
                                 addcoredensity=True, a=None):
        return self.xc.calculate_paw_correction(setup, D_sp, dEdD_sp,
                                 addcoredensity, a)
    
    def initialize(self, density, hamiltonian, wfs, occupations):
        assert wfs.gamma
        self.xc.initialize(density, hamiltonian, wfs, occupations)
        self.kpt_comm = wfs.kpt_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)
        
        if self.finegrid:
            self.poissonsolver = hamiltonian.poisson
            self.ghat = density.ghat
            self.interpolator = density.interpolator
            self.restrictor = hamiltonian.restrictor
        else:
            self.poissonsolver = PoissonSolver(eps=1e-11)
            self.poissonsolver.set_grid_descriptor(density.gd)
            self.poissonsolver.initialize()
            self.ghat = LFC(density.gd,
                            [setup.ghat_l for setup in density.setups],
                            integral=np.sqrt(4 * np.pi), forces=True)
        self.gd = density.gd
        self.finegd = self.ghat.gd

    def set_positions(self, spos_ac):
        if not self.finegrid:
            self.ghat.set_positions(spos_ac)
    
    def calculate(self, gd, n_sg, v_sg=None, e_g=None):
        # Normal XC contribution:
        exc = self.xc.calculate(gd, n_sg, v_sg, e_g)
        self.ekin = self.kpt_comm.sum(self.ekin_s.sum())
        return exc + self.kpt_comm.sum(self.exx_s.sum())

    def calculate_exx(self):
        for kpt in self.kpt_u:
            self.apply_orbital_dependent_hamiltonian(kpt, kpt.psit_nG)

    def apply_orbital_dependent_hamiltonian(self, kpt, psit_nG,
                                            Htpsit_nG=None, dH_asp=None):
        if kpt.f_n is None:
            return
        
        deg = 2 // self.nspins   # Spin degeneracy
        hybrid = self.hybrid
        
        P_ani = kpt.P_ani
        setups = self.setups

        vt_g = self.finegd.empty()
        if self.gd is not self.finegd:
            vt_G = self.gd.empty()

        nocc = int(kpt.f_n.sum()) // (3 - self.nspins)
        if self.unocc:
            nbands = len(kpt.f_n)
        else:
            nbands = nocc
        self.nocc_s[kpt.s] = nocc

        if Htpsit_nG is not None:
            kpt.vt_nG = self.gd.empty(nbands)
            kpt.vxx_ani = {}
            kpt.vxx_anii = {}
            for a, P_ni in P_ani.items():
                I = P_ni.shape[1]
                kpt.vxx_ani[a] = np.zeros((nbands, I))
                kpt.vxx_anii[a] = np.zeros((nbands, I, I))

        exx = 0.0
        ekin = 0.0

        # Determine pseudo-exchange
        for n1 in range(nbands):
            psit1_G = psit_nG[n1]
            f1 = kpt.f_n[n1] / deg
            for n2 in range(n1, nbands):
                psit2_G = psit_nG[n2]
                f2 = kpt.f_n[n2] / deg

                # Double count factor:
                dc = (1 + (n1 != n2)) * deg
                
                nt_G, rhot_g = self.calculate_pair_density(n1, n2, psit_nG,
                                                           P_ani)
                vt_g[:] = 0.0
                iter = self.poissonsolver.solve(vt_g, -rhot_g,
                                                charge=-float(n1 == n2),
                                                eps=1e-12,
                                                zero_initial_phi=True)
                vt_g *= hybrid

                if self.gd is self.finegd:
                    vt_G = vt_g
                else:
                    self.restrictor.apply(vt_g, vt_G)

                # Integrate the potential on fine and coarse grids
                int_fine = self.finegd.integrate(vt_g * rhot_g)
                int_coarse = self.gd.integrate(vt_G * nt_G)
                if self.gd.comm.rank == 0:  # only add to energy on master CPU
                    exx += 0.5 * dc * f1 * f2 * int_fine
                    ekin -= dc * f1 * f2 * int_coarse
                if Htpsit_nG is not None:
                    Htpsit_nG[n1] += f2 * vt_G * psit2_G
                    if n1 == n2:
                        kpt.vt_nG[n1] = f1 * vt_G
                    else:
                        Htpsit_nG[n2] += f1 * vt_G * psit1_G

                    # Update the vxx_uni and vxx_unii vectors of the nuclei,
                    # used to determine the atomic hamiltonian, and the 
                    # residuals
                    v_aL = self.ghat.dict()
                    self.ghat.integrate(vt_g, v_aL)
                    for a, v_L in v_aL.items():
                        v_ii = unpack(np.dot(setups[a].Delta_pL, v_L))
                        v_ni = kpt.vxx_ani[a]
                        v_nii = kpt.vxx_anii[a]
                        P_ni = P_ani[a]
                        v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2])
                        if n1 != n2:
                            v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1])
                        else:
                            # XXX Check this:
                            v_nii[n1] = f1 * v_ii

        # Apply the atomic corrections to the energy and the Hamiltonian matrix
        for a, P_ni in P_ani.items():
            setup = setups[a]

            if Htpsit_nG is not None:
                # Add non-trivial corrections the Hamiltonian matrix
                h_nn = symmetrize(np.inner(P_ni[:nbands], 
                                           kpt.vxx_ani[a][:nbands]))
                ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal())

                dH_p = dH_asp[a][kpt.s]
            
            # Get atomic density and Hamiltonian matrices
            D_p  = self.density.D_asp[a][kpt.s]
            D_ii = unpack2(D_p)
            ni = len(D_ii)
            
            # Add atomic corrections to the valence-valence exchange energy
            # --
            # >  D   C     D
            # --  ii  iiii  ii
            for i1 in range(ni):
                for i2 in range(ni):
                    A = 0.0
                    for i3 in range(ni):
                        p13 = packed_index(i1, i3, ni)
                        for i4 in range(ni):
                            p24 = packed_index(i2, i4, ni)
                            A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                    p12 = packed_index(i1, i2, ni)
                    if Htpsit_nG is not None:
                        dH_p[p12] -= 2 * hybrid / deg * A / ((i1 != i2) + 1)
                    ekin += 2 * hybrid / deg * D_ii[i1, i2] * A
                    exx -= hybrid / deg * D_ii[i1, i2] * A
            
            # Add valence-core exchange energy
            # --
            # >  X   D
            # --  ii  ii
            if setup.X_p is not None:
                exx -= hybrid * np.dot(D_p, setup.X_p)
                if Htpsit_nG is not None:
                    dH_p -= hybrid * setup.X_p
                    ekin += hybrid * np.dot(D_p, setup.X_p)

                # Add core-core exchange energy
                if kpt.s == 0:
                    exx += hybrid * setup.ExxC

        self.exx_s[kpt.s] = self.gd.comm.sum(exx)
        self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)

    def correct_hamiltonian_matrix(self, kpt, H_nn):
        if not hasattr(kpt, 'vxx_ani'):
            return

        if self.gd.comm.rank > 0:
            H_nn[:] = 0.0
            
        nocc = self.nocc_s[kpt.s]
        nbands = len(kpt.vt_nG)
        for a, P_ni in kpt.P_ani.items():
            H_nn[:nbands, :nbands] += symmetrize(np.inner(P_ni[:nbands],
                                                          kpt.vxx_ani[a]))
        self.gd.comm.sum(H_nn)
        
        H_nn[:nocc, nocc:] = 0.0
        H_nn[nocc:, :nocc] = 0.0

    def calculate_pair_density(self, n1, n2, psit_nG, P_ani):
        Q_aL = {}
        for a, P_ni in P_ani.items():
            P1_i = P_ni[n1]
            P2_i = P_ni[n2]
            D_ii = np.outer(P1_i, P2_i.conj()).real
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)
            
        nt_G = psit_nG[n1] * psit_nG[n2]

        if self.finegd is self.gd:
            nt_g = nt_G
        else:
            nt_g = self.finegd.empty()
            self.interpolator.apply(nt_G, nt_g)

        rhot_g = nt_g.copy()
        self.ghat.add(rhot_g, Q_aL)

        return nt_G, rhot_g

    def add_correction(self, kpt, psit_xG, Htpsit_xG, P_axi, c_axi, n_x,
                       calculate_change=False):
        if kpt.f_n is None:
            return

        nocc = self.nocc_s[kpt.s]
        
        if calculate_change:
            for x, n in enumerate(n_x):
                if n < nocc:
                    Htpsit_xG[x] += kpt.vt_nG[n] * psit_xG[x]
                    for a, P_xi in P_axi.items():
                        c_axi[a][x] += np.dot(kpt.vxx_anii[a][n], P_xi[x])
        else:
            for a, c_xi in c_axi.items():
                c_xi[:nocc] += kpt.vxx_ani[a][:nocc]
        
    def rotate(self, kpt, U_nn):
        if kpt.f_n is None:
            return

        nocc = self.nocc_s[kpt.s]
        if len(kpt.vt_nG) == nocc:
            U_nn = U_nn[:nocc, :nocc]
        gemm(1.0, kpt.vt_nG.copy(), U_nn, 0.0, kpt.vt_nG)
        for v_ni in kpt.vxx_ani.values():
            gemm(1.0, v_ni.copy(), U_nn, 0.0, v_ni)
        for v_nii in kpt.vxx_anii.values():
            gemm(1.0, v_nii.copy(), U_nn, 0.0, v_nii)
예제 #29
0
class OmegaMatrix:
    """
    Omega matrix in Casidas linear response formalism

    Parameters
      - calculator: the calculator object the ground state calculation
      - kss: the Kohn-Sham singles object
      - xc: the exchange correlation approx. to use
      - derivativeLevel: which level i of d^i Exc/dn^i to use
      - numscale: numeric epsilon for derivativeLevel=0,1
      - filehandle: the oject can be read from a filehandle
      - txt: output stream or file name
      - finegrid: level of fine grid to use. 0: nothing, 1 for poisson only,
        2 everything on the fine grid
    """
    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, firsttime = initialize_text_stream(txt, mpi.rank)

        if eh_comm == 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)
        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_full(self):

        self.paw.timer.start('Omega RPA')
        self.get_rpa()
        self.paw.timer.stop()

        if self.xc is not None:
            self.paw.timer.start('Omega XC')
            self.get_xc()
            self.paw.timer.stop()

        self.eh_comm.sum(self.Om)
        self.full = self.Om

    def get_xc(self):
        """Add xc part of the coupling matrix"""

        # shorthands
        paw = self.paw
        wfs = paw.wfs
        gd = paw.density.finegd
        comm = gd.comm
        eh_comm = self.eh_comm
        
        fg = self.finegrid is 2
        kss = self.fullkss
        nij = len(kss)

        Om_xc = self.Om
        # initialize densities
        # nt_sg is the smooth density on the fine grid with spin index

        if kss.nvspins==2:
            # spin polarised ground state calc.
            nt_sg = paw.density.nt_sg
        else:
            # spin unpolarised ground state calc.
            if kss.npspins==2:
                # construct spin polarised densities
                nt_sg = np.array([.5*paw.density.nt_sg[0],
                                  .5*paw.density.nt_sg[0]])
            else:
                nt_sg = paw.density.nt_sg
        # check if D_sp have been changed before
        D_asp = self.paw.density.D_asp
        for a, D_sp in D_asp.items():
            if len(D_sp) != kss.npspins:
                if len(D_sp) == 1:
                    D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]])
                else:
                    D_asp[a] = np.array([D_sp[0] + D_sp[1]])
                
        # restrict the density if needed
        if fg:
            nt_s = nt_sg
        else:
            nt_s = self.gd.zeros(nt_sg.shape[0])
            for s in range(nt_sg.shape[0]):
                self.restrict(nt_sg[s], nt_s[s])
            gd = paw.density.gd
                
        # initialize vxc or fxc

        if self.derivativeLevel==0:
            raise NotImplementedError
            if kss.npspins==2:
                v_g=nt_sg[0].copy()
            else:
                v_g=nt_sg.copy()
        elif self.derivativeLevel==1:
            pass
        elif self.derivativeLevel==2:
            fxc_sg = np.zeros(nt_sg.shape)
            self.xc.calculate_fxc(gd, nt_sg, fxc_sg)
        else:
            raise ValueError('derivativeLevel can only be 0,1,2')

##        self.paw.my_nuclei = []

        ns=self.numscale
        xc=self.xc
        print >> self.txt, 'XC',nij,'transitions'
        for ij in range(eh_comm.rank, nij, eh_comm.size):
            print >> self.txt,'XC kss['+'%d'%ij+']' 

            timer = Timer()
            timer.start('init')
            timer2 = Timer()
                      
            if self.derivativeLevel >= 1:
                # vxc is available
                # We use the numerical two point formula for calculating
                # the integral over fxc*n_ij. The results are
                # vvt_s        smooth integral
                # nucleus.I_sp atom based correction matrices (pack2)
                #              stored on each nucleus
                timer2.start('init v grids')
                vp_s=np.zeros(nt_s.shape,nt_s.dtype.char)
                vm_s=np.zeros(nt_s.shape,nt_s.dtype.char)
                if kss.npspins == 2: # spin polarised
                    nv_s = nt_s.copy()
                    nv_s[kss[ij].pspin] += ns * kss[ij].get(fg)
                    xc.calculate(gd, nv_s, vp_s)
                    nv_s = nt_s.copy()
                    nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg)
                    xc.calculate(gd, nv_s, vm_s)
                else: # spin unpolarised
                    nv = nt_s + ns * kss[ij].get(fg)
                    xc.calculate(gd, nv, vp_s)
                    nv = nt_s - ns * kss[ij].get(fg)
                    xc.calculate(gd, nv, vm_s)
                vvt_s = (0.5 / ns) * (vp_s - vm_s)
                timer2.stop()

                # initialize the correction matrices
                timer2.start('init v corrections')
                I_asp = {}
                for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items():
                    # create the modified density matrix
                    Pi_i = P_ni[kss[ij].i]
                    Pj_i = P_ni[kss[ij].j]
                    P_ii = np.outer(Pi_i, Pj_i)
                    # we need the symmetric form, hence we can pack
                    P_p = pack(P_ii)
                    D_sp = self.paw.density.D_asp[a].copy()
                    D_sp[kss[ij].pspin] -= ns * P_p
                    setup = wfs.setups[a]
                    I_sp = np.zeros_like(D_sp)
                    self.xc.calculate_paw_correction(setup, D_sp, I_sp)
                    I_sp *= -1.0
                    D_sp = self.paw.density.D_asp[a].copy()
                    D_sp[kss[ij].pspin] += ns * P_p
                    self.xc.calculate_paw_correction(setup, D_sp, I_sp)
                    I_sp /= 2.0 * ns
                    I_asp[a] = I_sp
                timer2.stop()
                    
            timer.stop()
            t0 = timer.get_time('init')
            timer.start(ij)
            
            for kq in range(ij,nij):
                weight = self.weight_Kijkq(ij, kq)
                
                if self.derivativeLevel == 0:
                    # only Exc is available
                    
                    if kss.npspins==2: # spin polarised
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] += kss[ij].get(fg)
                        nv_g[kss[kq].pspin] += kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(
                            nv_g[0], v_g, nv_g[1], v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] += kss[ij].get(fg)
                        nv_g[kss[kq].pspin] -= kss[kq].get(fg)
                        Excpm = xc.get_energy_and_potential(\
                                            nv_g[0],v_g,nv_g[1],v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] -=\
                                        kss[ij].get(fg)
                        nv_g[kss[kq].pspin] +=\
                                        kss[kq].get(fg)
                        Excmp = xc.get_energy_and_potential(\
                                            nv_g[0],v_g,nv_g[1],v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] -= \
                                        kss[ij].get(fg)
                        nv_g[kss[kq].pspin] -=\
                                        kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(\
                                            nv_g[0],v_g,nv_g[1],v_g)
                    else: # spin unpolarised
                        nv_g=nt_sg + ns*kss[ij].get(fg)\
                              + ns*kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(nv_g,v_g)
                        nv_g=nt_sg + ns*kss[ij].get(fg)\
                              - ns*kss[kq].get(fg)
                        Excpm = xc.get_energy_and_potential(nv_g,v_g)
                        nv_g=nt_sg - ns*kss[ij].get(fg)\
                              + ns*kss[kq].get(fg)
                        Excmp = xc.get_energy_and_potential(nv_g,v_g)
                        nv_g=nt_sg - ns*kss[ij].get(fg)\
                              - ns*kss[kq].get(fg)
                        Excmm = xc.get_energy_and_potential(nv_g,v_g)

                    Om_xc[ij,kq] += weight *\
                                0.25*(Excpp-Excmp-Excpm+Excmm)/(ns*ns)
                              
                elif self.derivativeLevel == 1:
                    # vxc is available

                    timer2.start('integrate')
                    Om_xc[ij,kq] += weight*\
                                 self.gd.integrate(kss[kq].get(fg)*
                                                   vvt_s[kss[kq].pspin])
                    timer2.stop()

                    timer2.start('integrate corrections')
                    Exc = 0.
                    for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items():
                        # create the modified density matrix
                        Pk_i = P_ni[kss[kq].i]
                        Pq_i = P_ni[kss[kq].j]
                        P_ii = np.outer(Pk_i, Pq_i)
                        # we need the symmetric form, hence we can pack
                        # use pack as I_sp used pack2
                        P_p = pack(P_ii)
                        Exc += np.dot(I_asp[a][kss[kq].pspin], P_p)
                    Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc)
                    timer2.stop()

                elif self.derivativeLevel == 2:
                    # fxc is available
                    if kss.npspins==2: # spin polarised
                        Om_xc[ij,kq] += weight *\
                            gd.integrate(kss[ij].get(fg) *
                                         kss[kq].get(fg) *
                                         fxc_sg[kss[ij].pspin, kss[kq].pspin])
                    else: # spin unpolarised
                        Om_xc[ij,kq] += weight *\
                            gd.integrate(kss[ij].get(fg) *
                                         kss[kq].get(fg) *
                                         fxc_sg)
                    
                    # XXX still numeric derivatives for local terms
                    timer2.start('integrate corrections')
                    Exc = 0.
                    for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items():
                        # create the modified density matrix
                        Pk_i = P_ni[kss[kq].i]
                        Pq_i = P_ni[kss[kq].j]
                        P_ii = np.outer(Pk_i, Pq_i)
                        # we need the symmetric form, hence we can pack
                        # use pack as I_sp used pack2
                        P_p = pack(P_ii)
                        Exc += np.dot(I_asp[a][kss[kq].pspin], P_p)
                    Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc)
                    timer2.stop()

                if ij != kq:
                    Om_xc[kq,ij] = Om_xc[ij,kq]
                
            timer.stop()
##            timer2.write()
            if ij < (nij-1):
                print >> self.txt,'XC estimated time left',\
                    self.time_left(timer, t0, ij, nij)


    def Coulomb_integral_kss(self, kss_ij, kss_kq, phit, rhot, 
                             timer=None):
        # smooth part
        if timer: 
            timer.start('integrate')
        I = self.gd.integrate(rhot * phit)
        if timer: 
            timer.stop()
            timer.start('integrate corrections 2')
        
        wfs = self.paw.wfs
        Pij_ani = wfs.kpt_u[kss_ij.spin].P_ani
        Pkq_ani = wfs.kpt_u[kss_kq.spin].P_ani

        # Add atomic corrections
        Ia = 0.0
        for a, Pij_ni in Pij_ani.items():
            Pi_i = Pij_ni[kss_ij.i]
            Pj_i = Pij_ni[kss_ij.j]
            Dij_ii = np.outer(Pi_i, Pj_i)
            Dij_p = pack(Dij_ii)
            Pk_i = Pkq_ani[a][kss_kq.i]
            Pq_i = Pkq_ani[a][kss_kq.j]
            Dkq_ii = np.outer(Pk_i, Pq_i)
            Dkq_p = pack(Dkq_ii)
            C_pp = wfs.setups[a].M_pp
            #   ----
            # 2 >      P   P  C    P  P
            #   ----    ip  jr prst ks qt
            #   prst
            Ia += 2.0*np.dot(Dkq_p, np.dot(C_pp, Dij_p))
        I += self.gd.comm.sum(Ia)
        if timer: 
            timer.stop()

        return I

    def get_rpa(self):
        """calculate RPA part of the omega matrix"""

        # shorthands
        kss=self.fullkss
        finegrid=self.finegrid
        wfs = self.paw.wfs
        eh_comm = self.eh_comm
        
        # calculate omega matrix
        nij = len(kss)
        print >> self.txt,'RPA',nij,'transitions'
        
        Om = self.Om
        
        for ij in range(eh_comm.rank, nij, eh_comm.size):
            print >> self.txt,'RPA kss['+'%d'%ij+']=', kss[ij]

            timer = Timer()
            timer.start('init')
            timer2 = Timer()
                      
            # smooth density including compensation charges
            timer2.start('with_compensation_charges 0')
            rhot_p = kss[ij].with_compensation_charges(
                finegrid is not 0)
            timer2.stop()
            
            # integrate with 1/|r_1-r_2|
            timer2.start('poisson')
            phit_p = np.zeros(rhot_p.shape, rhot_p.dtype.char)
            self.poisson.solve(phit_p, rhot_p, charge=None)
            timer2.stop()

            timer.stop()
            t0 = timer.get_time('init')
            timer.start(ij)

            if finegrid == 1:
                rhot = kss[ij].with_compensation_charges()
                phit = self.gd.zeros()
##                print "shapes 0=",phit.shape,rhot.shape
                self.restrict(phit_p,phit)
            else:
                phit = phit_p
                rhot = rhot_p

            for kq in range(ij,nij):
                if kq != ij:
                    # smooth density including compensation charges
                    timer2.start('kq with_compensation_charges')
                    rhot = kss[kq].with_compensation_charges(
                        finegrid is 2)
                    timer2.stop()

                pre = 2 * sqrt(kss[ij].get_energy() * kss[kq].get_energy() *
                               kss[ij].get_weight() * kss[kq].get_weight()  )
                I = self.Coulomb_integral_kss(kss[ij], kss[kq],
                                              rhot, phit, timer2)
                Om[ij,kq] = pre * I
                    
                if ij == kq:
                    Om[ij,kq] += kss[ij].get_energy()**2
                else:
                    Om[kq,ij]=Om[ij,kq]

            timer.stop()
##            timer2.write()
            if ij < (nij-1):
                t = timer.get_time(ij) # time for nij-ij calculations
                t = .5*t*(nij-ij)  # estimated time for n*(n+1)/2, n=nij-(ij+1)
                print >> self.txt,'RPA estimated time left',\
                      self.timestring(t0*(nij-ij-1)+t)

    def singlets_triplets(self):
        """Split yourself into singlet and triplet transitions"""

        assert(self.fullkss.npspins == 2)
        assert(self.fullkss.nvspins == 1)
        
        # strip kss from down spins
        skss = KSSingles()
        tkss = KSSingles()
        map = []
        for ij, ks in enumerate(self.fullkss):
            if ks.pspin == ks.spin:
                skss.append((ks + ks) / sqrt(2))
                tkss.append((ks - ks) / sqrt(2))
                map.append(ij)
            
        nkss = len(skss)

        # define the singlet and the triplet omega-matrixes
        sOm = OmegaMatrix(kss=skss)
        sOm.full = np.empty((nkss, nkss))
        tOm = OmegaMatrix(kss=tkss)
        tOm.full = np.empty((nkss, nkss))
        for ij in range(nkss):
            for kl in range(nkss):
                sOm.full[ij, kl] = (self.full[map[ij], map[kl]] +
                                    self.full[map[ij], nkss + map[kl]])
                tOm.full[ij, kl] = (self.full[map[ij], map[kl]] -
                                    self.full[map[ij], nkss + map[kl]])
        return sOm, tOm

    def timestring(self, t):
        ti = int(t + 0.5)
        td = ti // 86400
        st = ''
        if td > 0:
            st += '%d' % td + 'd'
            ti -= td * 86400
        th = ti // 3600
        if th > 0:
            st += '%d' % th + 'h'
            ti -= th * 3600
        tm = ti // 60
        if tm > 0:
            st += '%d' % tm + 'm'
            ti -= tm * 60
        st += '%d' % ti + 's'
        return st

    def time_left(self, timer, t0, ij, nij):
        t = timer.get_time(ij) # time for nij-ij calculations
        t = .5 * t * (nij - ij)  # estimated time for n*(n+1)/2, n=nij-(ij+1)
        return self.timestring(t0 * (nij - ij - 1) + t)

    def get_map(self, istart=None, jend=None, energy_range=None):
        """Return the reduction map for the given requirements"""

        self.istart = istart
        self.jend = jend
        if istart is None and jend is None and energy_range is None:
            return None, self.fullkss

        # reduce the matrix
        print >> self.txt,'# diagonalize: %d transitions original'\
                  % len(self.fullkss)

        if energy_range is None:
            if istart is None: istart = self.kss.istart
            if self.fullkss.istart > istart:
                raise RuntimeError('istart=%d has to be >= %d' %
                                   (istart, self.kss.istart))
            if jend is None: jend = self.kss.jend
            if self.fullkss.jend < jend:
                raise RuntimeError('jend=%d has to be <= %d' %
                                   (jend, self.kss.jend))

        else:
            try:
                emin, emax = energy_range
            except:
                emax = energy_range
                emin = 0.
            emin /= Hartree
            emax /= Hartree

        map= []
        kss = KSSingles()
        for ij, k in zip(range(len(self.fullkss)), self.fullkss):
            if energy_range is None:
                if k.i >= istart and k.j <= jend:
                    kss.append(k)
                    map.append(ij)
            else:
                if k.energy >= emin and k.energy < emax:
                    kss.append(k)
                    map.append(ij)
        kss.update()
        print >> self.txt, '# diagonalize: %d transitions now' % len(kss)
            
        return map, kss

    def diagonalize(self, istart=None, jend=None, energy_range=None,
                    TDA=False):
        """Evaluate Eigenvectors and Eigenvalues:"""

        if TDA:
            raise NotImplementedError

        map, kss = self.get_map(istart, jend, energy_range)
        nij = len(kss)
        if map is None:
            evec = self.full.copy()
        else:
            evec = np.zeros((nij,nij))
            for ij in range(nij):
                for kq in range(nij):
                    evec[ij,kq] = self.full[map[ij],map[kq]]
        assert(len(evec) > 0)

        self.eigenvectors = evec        
        self.eigenvalues = np.zeros((len(kss)))
        self.kss = kss
        diagonalize(self.eigenvectors, self.eigenvalues)

    def Kss(self, kss=None):
        """Set and get own Kohn-Sham singles"""
        if kss is not None:
            self.fullkss = kss
        if(hasattr(self,'fullkss')):
            return self.fullkss
        else:
            return None
 
    def read(self, filename=None, fh=None):
        """Read myself from a file"""
        if fh is None:
            f = open(filename, 'r')
        else:
            f = fh

        f.readline()
        nij = int(f.readline())
        full = np.zeros((nij,nij))
        for ij in range(nij):
            l = f.readline().split()
            for kq in range(ij,nij):
                full[ij,kq] = float(l[kq-ij])
                full[kq,ij] = full[ij,kq]
        self.full = full

        if fh is None:
            f.close()

    def write(self, filename=None, fh=None):
        """Write current state to a file."""
        if mpi.rank == mpi.MASTER:
            if fh is None:
                f = open(filename, 'w')
            else:
                f = fh

            f.write('# OmegaMatrix\n')
            nij = len(self.fullkss)
            f.write('%d\n' % nij)
            for ij in range(nij):
                for kq in range(ij,nij):
                    f.write(' %g' % self.full[ij,kq])
                f.write('\n')
            
            if fh is None:
                f.close()

    def weight_Kijkq(self, ij, kq):
        """weight for the coupling matrix terms"""
        kss = self.fullkss
        return 2.*sqrt( kss[ij].get_energy() * kss[kq].get_energy() *
                        kss[ij].get_weight() * kss[kq].get_weight()   )

    def __str__(self):
        str='<OmegaMatrix> '
        if hasattr(self,'eigenvalues'):
            str += 'dimension '+ ('%d'%len(self.eigenvalues))
            str += "\neigenvalues: "
            for ev in self.eigenvalues:
                str += ' ' + ('%f'%(sqrt(ev) * Hartree))
        return str
예제 #30
0
import numpy as np
from ase import Atoms
from gpaw import GPAW
from gpaw.tddft import TDDFT
from gpaw.inducedfield.inducedfield_base import BaseInducedField
from gpaw.inducedfield.inducedfield_tddft import TDDFTInducedField
from gpaw.poisson import PoissonSolver
from gpaw.test import equal

do_print_values = False  # Use this for printing the reference values
poisson_eps = 1e-12
density_eps = 1e-6

# PoissonSolver
poissonsolver = PoissonSolver('fd', eps=poisson_eps)

# Na2 cluster
atoms = Atoms(symbols='Na2',
              positions=[(0, 0, 0), (3.0, 0, 0)],
              pbc=False)
atoms.center(vacuum=3.0)

# Standard ground state calculation
calc = GPAW(nbands=2, h=0.6, setups={'Na': '1'}, poissonsolver=poissonsolver,
            convergence={'density': density_eps})
atoms.set_calculator(calc)
energy = atoms.get_potential_energy()
calc.write('na2_gs.gpw', mode='all')

# Standard time-propagation initialization
time_step = 10.0
예제 #31
0
from ase.io import read
from gpaw import GPAW, ConvergenceError
from gpaw.poisson import PoissonSolver
from gpaw.dipole_correction import DipoleCorrection

atoms = read('Pt_H2O.xyz')
atoms.set_cell([[  8.527708,   0.,         0.,      ],
               [  0.,         4.923474,   0.,      ],
               [  0.,         0.,        16.,      ]],
              scale_atoms=False)
atoms.center(axis=2)

atoms.pbc = (True, True, False)

atoms.calc = GPAW(h=0.20,
                  kpts=(2,4,1),
                  xc='RPBE',
                  poissonsolver=DipoleCorrection(PoissonSolver(),2),
                  basis='dzp',
                  maxiter=200,
                  width=0.1,
                  txt='Pt_H2O.txt',
                  )
ncpus = 8
예제 #32
0
 def initialize(self):
     PoissonSolver.initialize(self)
     r_gv = self.gd.get_grid_point_coordinates().transpose((1, 2, 3, 0))
     self.mask_g = self.get_mask(r_gv).astype(float)
     self.volume = self.gd.comm.sum(self.mask_g.sum()) * self.gd.dv
예제 #33
0
파일: poisson.py 프로젝트: yihsuanliu/gpaw
    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 -= gd.integrate(a) / L**3

    I = gd.integrate(a)
    b = gd.zeros()
    p.solve(b, a, charge=0)  #, eps=1e-20)
    return gd.collect(b, broadcast=1)


b1 = f(8, PoissonSolver(nn=1, relax='J'))
b2 = f(8, PoissonSolver(nn=1, relax='GS'))

err1 = abs(b1[0, 0, 0] - b1[8, 8, 8])
err2 = abs(b2[0, 0, 0] - b2[8, 8, 8])

print err1
print err2

assert err1 < 6e-16
assert err2 < 3e-6  # XXX Shouldn't this be better?

from gpaw.mpi import size
if size == 1:
    b3 = f(8, FFTPoissonSolver())
    err3 = abs(b3[0, 0, 0] - b3[8, 8, 8])
예제 #34
0
 def __init__(self, k2=0.0, nn='M', relax='GS', eps=2e-10):
     assert k2 <= 0, 'Currently only defined for k^2<=0'
     PoissonSolver.__init__(self, nn, relax, eps)
     self.k2 = k2
예제 #35
0
from gpaw.grid_descriptor import GridDescriptor
from gpaw.test import equal
from gpaw.mpi import world
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)
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)
예제 #36
0
from gpaw.mpi import world

from gpaw.test import equal

# Atoms
atoms = molecule('Na2')
atoms.center(vacuum=4.0)

# Ground-state calculation
calc = GPAW(nbands=2,
            h=0.4,
            setups=dict(Na='1'),
            basis='sz(dzp)',
            mode='lcao',
            xc='oldLDA',
            poissonsolver=PoissonSolver(eps=1e-16),
            convergence={'density': 1e-8},
            txt='gs.out')
atoms.set_calculator(calc)
energy = atoms.get_potential_energy()
calc.write('gs.gpw', mode='all')

# Time-propagation calculation
td_calc = LCAOTDDFT('gs.gpw', txt='td.out')
DipoleMomentWriter(td_calc, 'dm.dat')
td_calc.absorption_kick([0, 0, 1e-5])
td_calc.propagate(30, 150)
photoabsorption_spectrum('dm.dat',
                         'spec.dat',
                         e_max=10,
                         width=0.5,
예제 #37
0
class HybridXC(HybridXCBase):
    def __init__(self,
                 name,
                 hybrid=None,
                 xc=None,
                 finegrid=False,
                 unocc=False,
                 omega=None,
                 excitation=None,
                 excited=0,
                 stencil=2):
        """Mix standard functionals with exact exchange.

        finegrid: boolean
            Use fine grid for energy functional evaluations ?
        unocc: boolean
            Apply vxx also to unoccupied states ?
        omega: float
            RSF mixing parameter
        excitation: string:
            Apply operator for improved virtual orbitals
            to unocc states? Possible modes:
                singlet: excitations to singlets
                triplet: excitations to triplets
                average: average between singlets and tripletts
                see f.e. http://dx.doi.org/10.1021/acs.jctc.8b00238
        excited: number
            Band to excite from - counted from H**O downwards

        """
        self.finegrid = finegrid
        self.unocc = unocc
        self.excitation = excitation
        self.excited = excited
        HybridXCBase.__init__(self,
                              name,
                              hybrid=hybrid,
                              xc=xc,
                              omega=omega,
                              stencil=stencil)

    def calculate_paw_correction(self,
                                 setup,
                                 D_sp,
                                 dEdD_sp=None,
                                 addcoredensity=True,
                                 a=None):
        return self.xc.calculate_paw_correction(setup, D_sp, dEdD_sp,
                                                addcoredensity, a)

    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 set_positions(self, spos_ac):
        self.ghat.set_positions(spos_ac)

    def calculate(self, gd, n_sg, v_sg=None, e_g=None):
        # Normal XC contribution:
        exc = self.xc.calculate(gd, n_sg, v_sg, e_g)
        # Note that the quantities passed are on the
        # density/Hamiltonian grids!
        # They may be distributed differently from own quantities.
        self.ekin = self.kpt_comm.sum(self.ekin_s.sum())
        return exc + self.kpt_comm.sum(self.exx_s.sum())

    def calculate_exx(self):
        for kpt in self.kpt_u:
            self.apply_orbital_dependent_hamiltonian(kpt, kpt.psit_nG)

    def apply_orbital_dependent_hamiltonian(self,
                                            kpt,
                                            psit_nG,
                                            Htpsit_nG=None,
                                            dH_asp=None):
        if kpt.f_n is None:
            return

        deg = 2 // self.nspins  # Spin degeneracy
        hybrid = self.hybrid
        P_ani = kpt.P_ani
        setups = self.setups
        is_cam = self.is_cam

        vt_g = self.finegd.empty()
        if self.gd is not self.finegd:
            vt_G = self.gd.empty()
        if self.rsf == 'Yukawa':
            y_vt_g = self.finegd.empty()
            # if self.gd is not self.finegd:
            #     y_vt_G = self.gd.empty()

        nocc = int(ceil(kpt.f_n.sum())) // (3 - self.nspins)
        if self.excitation is not None:
            ex_band = nocc - self.excited - 1
            if self.excitation == 'singlet':
                ex_weight = -1
            elif self.excitation == 'triplet':
                ex_weight = +1
            else:
                ex_weight = 0

        if self.unocc or self.excitation is not None:
            nbands = len(kpt.f_n)
        else:
            nbands = nocc
        self.nocc_s[kpt.s] = nocc

        if Htpsit_nG is not None:
            kpt.vt_nG = self.gd.empty(nbands)
            kpt.vxx_ani = {}
            kpt.vxx_anii = {}
            for a, P_ni in P_ani.items():
                I = P_ni.shape[1]
                kpt.vxx_ani[a] = np.zeros((nbands, I))
                kpt.vxx_anii[a] = np.zeros((nbands, I, I))

        exx = 0.0
        ekin = 0.0

        # XXXX nbands can be different numbers on different cpus!
        # That means some will execute the loop and others not.
        # And deadlocks with augment-grids.

        # Determine pseudo-exchange
        for n1 in range(nbands):
            psit1_G = psit_nG[n1]
            f1 = kpt.f_n[n1] / deg
            for n2 in range(n1, nbands):
                psit2_G = psit_nG[n2]
                f2 = kpt.f_n[n2] / deg
                if n1 != n2 and f1 == 0 and f1 == f2:
                    continue  # Don't work on double unocc. bands
                # Double count factor:
                dc = (1 + (n1 != n2)) * deg
                nt_G, rhot_g = self.calculate_pair_density(
                    n1, n2, psit_nG, P_ani)
                vt_g[:] = 0.0
                # XXXXX This will go wrong because we are solving the
                # Poisson equation on the distribution of gd, not finegd
                # Or maybe it's fixed now

                self.poissonsolver.solve(vt_g,
                                         -rhot_g,
                                         charge=-float(n1 == n2),
                                         eps=1e-12,
                                         zero_initial_phi=True)
                vt_g *= hybrid
                if self.rsf == 'Yukawa':
                    y_vt_g[:] = 0.0
                    self.screened_poissonsolver.solve(y_vt_g,
                                                      -rhot_g,
                                                      charge=-float(n1 == n2),
                                                      eps=1e-12,
                                                      zero_initial_phi=True)
                    if is_cam:  # Cam like correction
                        y_vt_g *= self.cam_beta
                    else:
                        y_vt_g *= hybrid
                    vt_g -= y_vt_g
                if self.gd is self.finegd:
                    vt_G = vt_g
                else:
                    self.restrictor.apply(vt_g, vt_G)

                # Integrate the potential on fine and coarse grids
                int_fine = self.finegd.integrate(vt_g * rhot_g)
                int_coarse = self.gd.integrate(vt_G * nt_G)
                if self.gd.comm.rank == 0:  # only add to energy on master CPU
                    exx += 0.5 * dc * f1 * f2 * int_fine
                    ekin -= dc * f1 * f2 * int_coarse
                if Htpsit_nG is not None:
                    Htpsit_nG[n1] += f2 * vt_G * psit2_G
                    if n1 == n2:
                        kpt.vt_nG[n1] = f1 * vt_G
                        if self.excitation is not None and n1 == ex_band:
                            Htpsit_nG[nocc:] += f1 * vt_G * psit_nG[nocc:]
                    else:
                        if self.excitation is None or n1 != ex_band \
                                or n2 < nocc:
                            Htpsit_nG[n2] += f1 * vt_G * psit1_G
                        else:
                            Htpsit_nG[n2] += f1 * ex_weight * vt_G * psit1_G

                    # Update the vxx_uni and vxx_unii vectors of the nuclei,
                    # used to determine the atomic hamiltonian, and the
                    # residuals
                    v_aL = self.ghat.dict()
                    self.ghat.integrate(vt_g, v_aL)
                    for a, v_L in v_aL.items():
                        v_ii = unpack(np.dot(setups[a].Delta_pL, v_L))
                        v_ni = kpt.vxx_ani[a]
                        v_nii = kpt.vxx_anii[a]
                        P_ni = P_ani[a]
                        v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2])
                        if n1 != n2:
                            if self.excitation is None or n1 != ex_band or \
                                    n2 < nocc:
                                v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1])
                            else:
                                v_ni[n2] += f1 * ex_weight * \
                                    np.dot(v_ii, P_ni[n1])
                        else:
                            # XXX Check this:
                            v_nii[n1] = f1 * v_ii
                            if self.excitation is not None and n1 == ex_band:
                                for nuoc in range(nocc, nbands):
                                    v_ni[nuoc] += f1 * \
                                        np.dot(v_ii, P_ni[nuoc])

        def calculate_vv(ni, D_ii, M_pp, weight, addme=False):
            """Calculate the local corrections depending on Mpp."""
            dexx = 0
            dekin = 0
            if not addme:
                addsign = -2.0
            else:
                addsign = 2.0
            for i1 in range(ni):
                for i2 in range(ni):
                    A = 0.0
                    for i3 in range(ni):
                        p13 = packed_index(i1, i3, ni)
                        for i4 in range(ni):
                            p24 = packed_index(i2, i4, ni)
                            A += M_pp[p13, p24] * D_ii[i3, i4]
                    p12 = packed_index(i1, i2, ni)
                    if Htpsit_nG is not None:
                        dH_p[p12] += addsign * weight / \
                            deg * A / ((i1 != i2) + 1)
                    dekin += 2 * weight / deg * D_ii[i1, i2] * A
                    dexx -= weight / deg * D_ii[i1, i2] * A
            return (dexx, dekin)

        # Apply the atomic corrections to the energy and the Hamiltonian
        # matrix
        for a, P_ni in P_ani.items():
            setup = setups[a]

            if Htpsit_nG is not None:
                # Add non-trivial corrections the Hamiltonian matrix
                h_nn = symmetrize(
                    np.inner(P_ni[:nbands], kpt.vxx_ani[a][:nbands]))
                ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal())

                dH_p = dH_asp[a][kpt.s]

            # Get atomic density and Hamiltonian matrices
            D_p = self.density.D_asp[a][kpt.s]
            D_ii = unpack2(D_p)
            ni = len(D_ii)

            # Add atomic corrections to the valence-valence exchange energy
            # --
            # >  D   C     D
            # --  ii  iiii  ii
            (dexx, dekin) = calculate_vv(ni, D_ii, setup.M_pp, hybrid)
            ekin += dekin
            exx += dexx
            if self.rsf is not None:
                Mg_pp = setup.calculate_yukawa_interaction(self.omega)
                if is_cam:
                    (dexx, dekin) = calculate_vv(ni,
                                                 D_ii,
                                                 Mg_pp,
                                                 self.cam_beta,
                                                 addme=True)
                else:
                    (dexx, dekin) = calculate_vv(ni,
                                                 D_ii,
                                                 Mg_pp,
                                                 hybrid,
                                                 addme=True)
                ekin -= dekin
                exx -= dexx
            # Add valence-core exchange energy
            # --
            # >  X   D
            # --  ii  ii
            if setup.X_p is not None:
                exx -= hybrid * np.dot(D_p, setup.X_p)
                if Htpsit_nG is not None:
                    dH_p -= hybrid * setup.X_p
                    ekin += hybrid * np.dot(D_p, setup.X_p)

                if self.rsf == 'Yukawa' and setup.X_pg is not None:
                    if is_cam:
                        thybrid = self.cam_beta  # 0th order
                    else:
                        thybrid = hybrid
                    exx += thybrid * np.dot(D_p, setup.X_pg)
                    if Htpsit_nG is not None:
                        dH_p += thybrid * setup.X_pg
                        ekin -= thybrid * np.dot(D_p, setup.X_pg)
                elif self.rsf == 'Yukawa' and setup.X_pg is None:
                    thybrid = exp(-3.62e-2 * self.omega)  # educated guess
                    if is_cam:
                        thybrid *= self.cam_beta
                    else:
                        thybrid *= hybrid
                    exx += thybrid * np.dot(D_p, setup.X_p)
                    if Htpsit_nG is not None:
                        dH_p += thybrid * setup.X_p
                        ekin -= thybrid * np.dot(D_p, setup.X_p)
                # Add core-core exchange energy
                if kpt.s == 0:
                    if self.rsf is None or is_cam:
                        if is_cam:
                            exx += self.cam_alpha * setup.ExxC
                        else:
                            exx += hybrid * setup.ExxC

        self.exx_s[kpt.s] = self.gd.comm.sum(exx)
        self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)

    def correct_hamiltonian_matrix(self, kpt, H_nn):
        if not hasattr(kpt, 'vxx_ani'):
            return

        # if self.gd.comm.rank > 0:
        #    H_nn[:] = 0.0

        nocc = self.nocc_s[kpt.s]
        nbands = len(kpt.vt_nG)
        for a, P_ni in kpt.P_ani.items():
            H_nn[:nbands, :nbands] += symmetrize(
                np.inner(P_ni[:nbands], kpt.vxx_ani[a]))
        # self.gd.comm.sum(H_nn)

        if not self.unocc or self.excitation is not None:
            H_nn[:nocc, nocc:] = 0.0
            H_nn[nocc:, :nocc] = 0.0

    def calculate_pair_density(self, n1, n2, psit_nG, P_ani):
        Q_aL = {}
        for a, P_ni in P_ani.items():
            P1_i = P_ni[n1]
            P2_i = P_ni[n2]
            D_ii = np.outer(P1_i, P2_i.conj()).real
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        nt_G = psit_nG[n1] * psit_nG[n2]

        if self.finegd is self.gd:
            nt_g = nt_G
        else:
            nt_g = self.finegd.empty()
            self.interpolator.apply(nt_G, nt_g)

        rhot_g = nt_g.copy()
        self.ghat.add(rhot_g, Q_aL)

        return nt_G, rhot_g

    def add_correction(self,
                       kpt,
                       psit_xG,
                       Htpsit_xG,
                       P_axi,
                       c_axi,
                       n_x,
                       calculate_change=False):
        if kpt.f_n is None:
            return

        if self.unocc or self.excitation is not None:
            nocc = len(kpt.vt_nG)
        else:
            nocc = self.nocc_s[kpt.s]

        if calculate_change:
            for x, n in enumerate(n_x):
                if n < nocc:
                    Htpsit_xG[x] += kpt.vt_nG[n] * psit_xG[x]
                    for a, P_xi in P_axi.items():
                        c_axi[a][x] += np.dot(kpt.vxx_anii[a][n], P_xi[x])
        else:
            for a, c_xi in c_axi.items():
                c_xi[:nocc] += kpt.vxx_ani[a][:nocc]

    def rotate(self, kpt, U_nn):
        if kpt.f_n is None:
            return

        U_nn = U_nn.T.copy()
        nocc = self.nocc_s[kpt.s]
        if len(kpt.vt_nG) == nocc:
            U_nn = U_nn[:nocc, :nocc]
        gemm(1.0, kpt.vt_nG.copy(), U_nn, 0.0, kpt.vt_nG)
        for v_ni in kpt.vxx_ani.values():
            gemm(1.0, v_ni.copy(), U_nn, 0.0, v_ni)
        for v_nii in kpt.vxx_anii.values():
            gemm(1.0, v_nii.copy(), U_nn, 0.0, v_nii)
예제 #38
0
    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, firsttime = initialize_text_stream(txt, mpi.rank)

        if eh_comm == 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)
        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()
예제 #39
0
    def set_grid_descriptor(self, qmgd):
        if not self.has_subsystems:
            return

        self.qm.gd = qmgd

        # Create quantum Poisson solver
        self.qm.poisson_solver = PoissonSolver(
            name='fd',
            nn=self.nn,
            eps=self.eps,
            relax=self.relax,
            remove_moment=self.remove_moment_qm)
        self.qm.poisson_solver.set_grid_descriptor(self.qm.gd)
        #self.qm.poisson_solver.initialize()
        self.qm.phi = self.qm.gd.zeros()
        self.qm.rho = self.qm.gd.zeros()

        # Set quantum grid descriptor
        self.qm.poisson_solver.set_grid_descriptor(qmgd)

        # Create classical PoissonSolver
        self.cl.poisson_solver = PoissonSolver(
            name='fd',
            nn=self.nn,
            eps=self.eps,
            relax=self.relax,
            remove_moment=self.remove_moment_cl)
        self.cl.poisson_solver.set_grid_descriptor(self.cl.gd)
        #self.cl.poisson_solver.initialize()

        # Initialize classical material,
        # its Poisson solver was generated already
        self.cl.poisson_solver.set_grid_descriptor(self.cl.gd)
        self.classical_material.initialize(self.cl.gd)
        self.cl.extrapolated_qm_phi = self.cl.gd.zeros()
        self.cl.phi = self.cl.gd.zeros()
        self.cl.extrapolated_qm_phi = self.cl.gd.empty()

        msg = self.messages.append
        msg('\nFDTDPoissonSolver/grid descriptors and coupler:')
        msg(' Domain parallelization with %i processes.' %
            self.cl.gd.comm.size)
        if self.cl.gd.comm == serial_comm:
            msg(' Communicator for domain parallelization: serial_comm')
        elif self.cl.gd.comm == world:
            msg(' Communicator for domain parallelization: world')
        elif self.cl.gd.comm == self.qm.gd.comm:
            msg(' Communicator for domain parallelization: dft_domain_comm')
        else:
            msg(' Communicator for domain parallelization: %s'
                % self.cl.gd.comm)

        # Initialize potential coupler
        if self.potential_coupling_scheme == 'Multipoles':
            msg('Classical-quantum coupling by multipole expansion ' +
                'with maxL: %i' % (self.remove_moment_qm))
            self.potential_coupler = MultipolesPotentialCoupler(
                qm=self.qm,
                cl=self.cl,
                index_offset_1=self.shift_indices_1,
                index_offset_2=self.shift_indices_2,
                extended_index_offset_1=self.extended_shift_indices_1,
                extended_index_offset_2=self.extended_shift_indices_2,
                extended_delta_index=self.extended_deltaIndex,
                num_refinements=self.num_refinements,
                remove_moment_qm=self.remove_moment_qm,
                remove_moment_cl=self.remove_moment_cl,
                rank=self.rank)
        else:
            msg('Classical-quantum coupling by coarsening/refining')
            self.potential_coupler = RefinerPotentialCoupler(
                qm=self.qm,
                cl=self.cl,
                index_offset_1=self.shift_indices_1,
                index_offset_2=self.shift_indices_2,
                extended_index_offset_1=self.extended_shift_indices_1,
                extended_index_offset_2=self.extended_shift_indices_2,
                extended_delta_index=self.extended_deltaIndex,
                num_refinements=self.num_refinements,
                remove_moment_qm=self.remove_moment_qm,
                remove_moment_cl=self.remove_moment_cl,
                rank=self.rank)

        self.phi_tot_clgd = self.cl.gd.empty()
        self.phi_tot_qmgd = self.qm.gd.empty()
예제 #40
0
    def read(self, reader):
        """Read state from file."""

        if isinstance(reader, str):
            reader = gpaw.io.open(reader, 'r')

        r = reader

        version = r['version']

        assert version >= 0.3

        self.xc = r['XCFunctional']
        self.nbands = r.dimension('nbands')
        self.spinpol = (r.dimension('nspins') == 2)

        if r.has_array('NBZKPoints'):
            self.kpts = r.get('NBZKPoints')
        else:
            self.kpts = r.get('BZKPoints')
        self.usesymm = r['UseSymmetry']
        try:
            self.basis = r['BasisSet']
        except KeyError:
            pass
        self.gpts = ((r.dimension('ngptsx') + 1) // 2 * 2,
                     (r.dimension('ngptsy') + 1) // 2 * 2,
                     (r.dimension('ngptsz') + 1) // 2 * 2)
        self.lmax = r['MaximumAngularMomentum']
        self.setups = r['SetupTypes']
        self.fixdensity = r['FixDensity']
        if version <= 0.4:
            # Old version: XXX
            print('# Warning: Reading old version 0.3/0.4 restart files ' +
                  'will be disabled some day in the future!')
            self.convergence['eigenstates'] = r['Tolerance']
        else:
            self.convergence = {
                'density': r['DensityConvergenceCriterion'],
                'energy': r['EnergyConvergenceCriterion'] * Hartree,
                'eigenstates': r['EigenstatesConvergenceCriterion'],
                'bands': r['NumberOfBandsToConverge']
            }
            if version <= 0.6:
                mixer = 'Mixer'
                weight = r['MixMetric']
            elif version <= 0.7:
                mixer = r['MixClass']
                weight = r['MixWeight']
                metric = r['MixMetric']
                if metric is None:
                    weight = 1.0
            else:
                mixer = r['MixClass']
                weight = r['MixWeight']

            if mixer == 'Mixer':
                from gpaw.mixer import Mixer
            elif mixer == 'MixerSum':
                from gpaw.mixer import MixerSum as Mixer
            elif mixer == 'MixerSum2':
                from gpaw.mixer import MixerSum2 as Mixer
            elif mixer == 'MixerDif':
                from gpaw.mixer import MixerDif as Mixer
            elif mixer == 'DummyMixer':
                from gpaw.mixer import DummyMixer as Mixer
            else:
                Mixer = None

            if Mixer is None:
                self.mixer = None
            else:
                self.mixer = Mixer(r['MixBeta'], r['MixOld'], weight)

        if version == 0.3:
            # Old version: XXX
            print('# Warning: Reading old version 0.3 restart files is ' +
                  'dangerous and will be disabled some day in the future!')
            self.stencils = (2, 3)
            self.charge = 0.0
            fixmom = False
        else:
            self.stencils = (r['KohnShamStencil'], r['InterpolationStencil'])
            if r['PoissonStencil'] == 999:
                self.poissonsolver = FFTPoissonSolver()
            else:
                self.poissonsolver = PoissonSolver(nn=r['PoissonStencil'])
            self.charge = r['Charge']
            fixmom = r['FixMagneticMoment']

        self.occupations = FermiDirac(r['FermiWidth'] * Hartree,
                                      fixmagmom=fixmom)

        try:
            self.mode = r['Mode']
        except KeyError:
            self.mode = 'fd'

        try:
            dtype = r['DataType']
            if dtype == 'Float':
                self.dtype = float
            else:
                self.dtype = complex
        except KeyError:
            self.dtype = float
예제 #41
0
    def calculate_induced_field(self,
                                from_density='comp',
                                gridrefinement=2,
                                extend_N_cd=None,
                                deextend=False,
                                poissonsolver=None,
                                gradient_n=3):
        if self.has_field and \
           from_density == self.field_from_density and \
           self.Frho_wg is not None:
            Frho_wg = self.Frho_wg
            gd = self.fieldgd
        else:
            Frho_wg, gd = self.get_induced_density(from_density,
                                                   gridrefinement)

        # Always extend a bit to get field without jumps
        if extend_N_cd is None:
            extend_N = max(8, 2**int(np.ceil(np.log(gradient_n) / np.log(2.))))
            extend_N_cd = extend_N * np.ones(shape=(3, 2), dtype=np.int)
            deextend = True

        # Extend grid
        oldgd = gd
        egd, cell_cv, move_c = \
            extended_grid_descriptor(gd, extend_N_cd=extend_N_cd)
        Frho_we = egd.zeros((self.nw, ), dtype=self.dtype)
        for w in range(self.nw):
            extend_array(gd, egd, Frho_wg[w], Frho_we[w])
        Frho_wg = Frho_we
        gd = egd
        if not deextend:
            # TODO: this will make atoms unusable with original grid
            self.atoms.set_cell(cell_cv, scale_atoms=False)
            move_atoms(self.atoms, move_c)

        # Allocate arrays
        Fphi_wg = gd.zeros((self.nw, ), dtype=self.dtype)
        Fef_wvg = gd.zeros((
            self.nw,
            self.nv,
        ), dtype=self.dtype)
        Ffe_wg = gd.zeros((self.nw, ), dtype=float)

        # Poissonsolver
        if poissonsolver is None:
            poissonsolver = PoissonSolver(name='fd', eps=1e-20)
        poissonsolver.set_grid_descriptor(gd)

        for w in range(self.nw):
            # TODO: better output of progress
            # parprint('%d' % w)
            calculate_field(gd,
                            Frho_wg[w],
                            self.Fbgef_v,
                            Fphi_wg[w],
                            Fef_wvg[w],
                            Ffe_wg[w],
                            poissonsolver=poissonsolver,
                            nv=self.nv,
                            gradient_n=gradient_n)

        # De-extend grid
        if deextend:
            Frho_wo = oldgd.zeros((self.nw, ), dtype=self.dtype)
            Fphi_wo = oldgd.zeros((self.nw, ), dtype=self.dtype)
            Fef_wvo = oldgd.zeros((
                self.nw,
                self.nv,
            ), dtype=self.dtype)
            Ffe_wo = oldgd.zeros((self.nw, ), dtype=float)
            for w in range(self.nw):
                deextend_array(oldgd, gd, Frho_wo[w], Frho_wg[w])
                deextend_array(oldgd, gd, Fphi_wo[w], Fphi_wg[w])
                deextend_array(oldgd, gd, Ffe_wo[w], Ffe_wg[w])
                for v in range(self.nv):
                    deextend_array(oldgd, gd, Fef_wvo[w][v], Fef_wvg[w][v])
            Frho_wg = Frho_wo
            Fphi_wg = Fphi_wo
            Fef_wvg = Fef_wvo
            Ffe_wg = Ffe_wo
            gd = oldgd

        # Store results
        self.has_field = True
        self.field_from_density = from_density
        self.fieldgd = gd
        self.Frho_wg = Frho_wg
        self.Fphi_wg = Fphi_wg
        self.Fef_wvg = Fef_wvg
        self.Ffe_wg = Ffe_wg
예제 #42
0

def compare(phi1_g, phi2_g, val, eps=np.sqrt(poissoneps)):
    big_phi1_g = gd.collect(phi1_g)
    big_phi2_g = gd.collect(phi2_g)
    if gd.comm.rank == 0:
        diff = np.max(np.absolute(big_phi1_g - big_phi2_g))
    else:
        diff = 0.0
    diff = np.array([diff])
    gd.comm.broadcast(diff, 0)
    equal(diff[0], val, eps)


# Get reference from default poissonsolver
poisson = PoissonSolver('fd', eps=poissoneps)
phiref_g, npoisson = poisson_init_solve(gd, rho_g, poisson)

# Test agreement with default
poisson = ExtraVacuumPoissonSolver(N_c, PoissonSolver('fd', eps=poissoneps))
phi_g, npoisson = poisson_init_solve(gd, rho_g, poisson)
compare(phi_g, phiref_g, 0.0, 1e-24)

# New reference with extra vacuum
gpts = N_c * 4
poisson = ExtraVacuumPoissonSolver(gpts, PoissonSolver('fd', eps=poissoneps))
phi_g, npoisson = poisson_init_solve(gd, rho_g, poisson)
# print poisson.get_description()
compare(phi_g, phiref_g, 2.6485385144e-02)
phiref_g = phi_g
예제 #43
0
from gpaw.utilities.gauss import Gaussian
from gpaw.grid_descriptor import GridDescriptor
from gpaw.test import equal
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):