Beispiel #1
0
 def test_something(self):
     laplace_uG = np.empty_like(self.laplace0_uG)
     op = Laplace(self.gd, dtype=self.dtype)
     for myu, laplace_G in enumerate(laplace_uG):
         phase_cd = {float:None, complex:self.phase_ucd[myu]}[self.dtype]
         op.apply(self.wf_uG[myu], laplace_G, phase_cd)
         print 'myu:', myu, 'diff:', np.std(laplace_G-self.laplace0_uG[myu]), '/', np.abs(laplace_G-self.laplace0_uG[myu]).max()
Beispiel #2
0
 def test_something(self):
     laplace_uG = np.empty_like(self.laplace0_uG)
     op = Laplace(self.gd, dtype=self.dtype)
     for myu, laplace_G in enumerate(laplace_uG):
         phase_cd = {float:None, complex:self.phase_ucd[myu]}[self.dtype]
         op.apply(self.wf_uG[myu], laplace_G, phase_cd)
         print 'myu:', myu, 'diff:', np.std(laplace_G-self.laplace0_uG[myu]), '/', np.abs(laplace_G-self.laplace0_uG[myu]).max()
Beispiel #3
0
def go(comm, ngpts, repeat, narrays, out, prec):
    N_c = np.array((ngpts, ngpts, ngpts))
    a = 10.0
    gd = GridDescriptor(N_c, (a, a, a), comm=comm))
    gdcoarse = gd.coarsen()
    gdfine = gd.refine()
    kin1 = Laplace(gd, -0.5, 1).apply
    laplace = Laplace(gd, -0.5, 2)
    kin2 = laplace.apply
    restrict = Transformer(gd, gdcoarse, 1).apply
    interpolate = Transformer(gd, gdfine, 1).apply
    precondition = Preconditioner(gd, laplace, np_float)
    a1 = gd.empty(narrays)
    a1[:] = 1.0
    a2 = gd.empty(narrays)
    c = gdcoarse.empty(narrays)
    f = gdfine.empty(narrays)

    T = [0, 0, 0, 0, 0]
    for i in range(repeat):
        comm.barrier()
        kin1(a1, a2)
        comm.barrier()
        t0a = time()
        kin1(a1, a2)
        t0b = time()
        comm.barrier()
        t1a = time()
        kin2(a1, a2)
        t1b = time()
        comm.barrier()
        t2a = time()
        for A, C in zip(a1,c):
            restrict(A, C)
        t2b = time()
        comm.barrier()
        t3a = time()
        for A, F in zip(a1,f):
            interpolate(A, F)
        t3b = time()
        comm.barrier()
        if prec:
            t4a = time()
            for A in a1:
                precondition(A, None, None, None)
            t4b = time()
            comm.barrier()

        T[0] += t0b - t0a
        T[1] += t1b - t1a
        T[2] += t2b - t2a
        T[3] += t3b - t3a
        if prec:
            T[4] += t4b - t4a

    if mpi.rank == 0:
        out.write(' %2d %2d %2d' % tuple(gd.parsize_c))
        out.write(' %12.6f %12.6f %12.6f %12.6f %12.6f\n' %
                  tuple([t / repeat / narrays for t in T]))
        out.flush()
Beispiel #4
0
    def __init__(self, hamiltonian, wfs, gd, dtype=float):
        """Save useful objects for the Sternheimer operator.

        Parameters
        ----------
        hamiltonian: Hamiltonian
            Hamiltonian for a ground-state calculation.
        wfs: WaveFunctions
            Ground-state wave-functions.
        gd: GridDescriptor
            Grid on which the operator is defined.
        dtype: dtype
            dtype of the wave-function being operated on.

        """

        self.hamiltonian = hamiltonian
        self.kin = Laplace(gd, scale=-0.5, n=3, dtype=dtype)
        self.kpt_u = wfs.kpt_u
        self.pt = wfs.pt
        self.gd = gd

        # Variables for k-point and band index
        self.k = None
        self.n = None
        self.kplusq = None

        # For scipy's linear solver
        N = np.prod(gd.n_c)
        self.shape = (N, N)
        self.dtype = dtype
Beispiel #5
0
    def __init__(self,
                 stencil,
                 parallel,
                 initksl,
                 gd,
                 nvalence,
                 setups,
                 bd,
                 dtype,
                 world,
                 kd,
                 kptband_comm,
                 timer,
                 reuse_wfs_method=None,
                 collinear=True):
        FDPWWaveFunctions.__init__(self,
                                   parallel,
                                   initksl,
                                   reuse_wfs_method=reuse_wfs_method,
                                   collinear=collinear,
                                   gd=gd,
                                   nvalence=nvalence,
                                   setups=setups,
                                   bd=bd,
                                   dtype=dtype,
                                   world=world,
                                   kd=kd,
                                   kptband_comm=kptband_comm,
                                   timer=timer)

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype)

        self.taugrad_v = None  # initialized by MGGA functional
Beispiel #6
0
    def set_grid_descriptor(self, gd):
        # Should probably be renamed initialize
        self.gd = gd
        scale = -0.25 / pi

        if self.nn == 'M':
            if not gd.orthogonal:
                raise RuntimeError('Cannot use Mehrstellen stencil with '
                                   'non orthogonal cell.')

            self.operators = [LaplaceA(gd, -scale)]
            self.B = LaplaceB(gd)
        else:
            self.operators = [Laplace(gd, scale, self.nn)]
            self.B = None

        self.interpolators = []
        self.restrictors = []

        level = 0
        self.presmooths = [2]
        self.postsmooths = [1]

        # Weights for the relaxation,
        # only used if 'J' (Jacobi) is chosen as method
        self.weights = [2.0 / 3.0]

        while level < 8:
            try:
                gd2 = gd.coarsen()
            except ValueError:
                break
            self.operators.append(Laplace(gd2, scale, 1))
            self.interpolators.append(Transformer(gd2, gd))
            self.restrictors.append(Transformer(gd, gd2))
            self.presmooths.append(4)
            self.postsmooths.append(4)
            self.weights.append(1.0)
            level += 1
            gd = gd2

        self.levels = level

        if self.operators[-1].gd.N_c.max() > 36:
            # Try to warn exactly once no matter how one uses the solver.
            if gd.comm.parent is None:
                warn = (gd.comm.rank == 0)
            else:
                warn = (gd.comm.parent.rank == 0)

            if warn:
                warntxt = '\n'.join([POISSON_GRID_WARNING, '',
                                     self.get_description()])
            else:
                warntxt = ('Poisson warning from domain rank %d'
                           % self.gd.comm.rank)

            # Warn from all ranks to avoid deadlocks.
            warnings.warn(warntxt, stacklevel=2)
 def apply_t(self):
     """Apply kinetic energy operator and return new object."""
     p = 2  # padding
     newsize_c = self.size_c + 2 * p
     gd = GridDescriptor(N_c=newsize_c + 1, cell_cv=self.gd.h_c * (newsize_c + 1), pbc_c=False, comm=mpi.serial_comm)
     T = Laplace(gd, scale=1 / 2.0, n=p)
     f_ig = np.zeros((len(self.f_iG),) + tuple(newsize_c))
     f_ig[:, p:-p, p:-p, p:-p] = self.f_iG
     Tf_iG = np.empty_like(f_ig)
     T.apply(f_ig, Tf_iG)
     return LocalizedFunctions(self.gd, Tf_iG, self.corner_c - p, self.index)
Beispiel #8
0
    def __init__(self, stencil, diagksl, orthoksl, initksl, gd, nvalence,
                 setups, bd, dtype, world, kd, kptband_comm, timer):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd,
                                   nvalence, setups, bd, dtype, world, kd,
                                   kptband_comm, timer)

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype)

        self.matrixoperator = MatrixOperator(self.orthoksl)

        self.taugrad_v = None  # initialized by MGGA functional
Beispiel #9
0
 def apply_t(self):
     """Apply kinetic energy operator and return new object."""
     p = 2  # padding
     newsize_c = self.size_c + 2 * p
     gd = GridDescriptor(N_c=newsize_c + 1,
                         cell_cv=self.gd.h_c * (newsize_c + 1),
                         pbc_c=False,
                         comm=mpi.serial_comm)
     T = Laplace(gd, scale =1/2., n=p)
     f_ig = np.zeros((len(self.f_iG),) + tuple(newsize_c))
     f_ig[:, p:-p, p:-p, p:-p] = self.f_iG
     Tf_iG = np.empty_like(f_ig)
     T.apply(f_ig, Tf_iG)
     return LocalizedFunctions(self.gd, Tf_iG, self.corner_c - p,
                               self.index)
    def __init__(self, hamiltonian, wfs, gd, dtype=float):
        """Save useful objects for the Sternheimer operator.

        Parameters
        ----------
        hamiltonian: Hamiltonian
            Hamiltonian for a ground-state calculation.
        wfs: WaveFunctions
            Ground-state wave-functions.
        gd: GridDescriptor
            Grid on which the operator is defined.
        dtype: dtype
            dtype of the wave-function being operated on.

        """

        self.hamiltonian = hamiltonian
        self.kin = Laplace(gd, scale=-0.5, n=3, dtype=dtype)
        self.kpt_u = wfs.kpt_u
        self.pt = wfs.pt
        self.gd = gd

        # Variables for k-point and band index
        self.k = None
        self.n = None
        self.kplusq = None
        
        # For scipy's linear solver
        N = np.prod(gd.n_c)
        self.shape = (N, N)
        self.dtype = dtype
Beispiel #11
0
    def set_grid_descriptor(self, gd):
        # Should probably be renamed initialize
        self.gd = gd
        self.dv = gd.dv

        gd = self.gd
        scale = -0.25 / pi

        if self.nn == 'M':
            if not gd.orthogonal:
                raise RuntimeError('Cannot use Mehrstellen stencil with '
                                   'non orthogonal cell.')

            self.operators = [LaplaceA(gd, -scale, allocate=False)]
            self.B = LaplaceB(gd, allocate=False)
        else:
            self.operators = [Laplace(gd, scale, self.nn, allocate=False)]
            self.B = None

        self.interpolators = []
        self.restrictors = []

        level = 0
        self.presmooths = [2]
        self.postsmooths = [1]

        # Weights for the relaxation,
        # only used if 'J' (Jacobi) is chosen as method
        self.weights = [2.0 / 3.0]

        while level < 4:
            try:
                gd2 = gd.coarsen()
            except ValueError:
                break
            self.operators.append(Laplace(gd2, scale, 1, allocate=False))
            self.interpolators.append(Transformer(gd2, gd, allocate=False))
            self.restrictors.append(Transformer(gd, gd2, allocate=False))
            self.presmooths.append(4)
            self.postsmooths.append(4)
            self.weights.append(1.0)
            level += 1
            gd = gd2

        self.levels = level
Beispiel #12
0
    def __init__(self, gd0, kin0, dtype=float, block=1):
        gd1 = gd0.coarsen()
        gd2 = gd1.coarsen()
        self.kin0 = kin0
        self.kin1 = Laplace(gd1, -0.5, 1, dtype)
        self.kin2 = Laplace(gd2, -0.5, 1, dtype)
        self.scratch0 = gd0.zeros((2, block), dtype, False)
        self.scratch1 = gd1.zeros((3, block),dtype, False)
        self.scratch2 = gd2.zeros((3, block), dtype, False)
        self.step = 0.66666666 / kin0.get_diagonal_element()

        self.restrictor_object0 = Transformer(gd0, gd1, 1,dtype)
        self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype)
        self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype)
        self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype)
        self.restrictor0 = self.restrictor_object0.apply
        self.restrictor1 = self.restrictor_object1.apply
        self.interpolator2 = self.interpolator_object2.apply
        self.interpolator1 = self.interpolator_object1.apply
Beispiel #13
0
    def __init__(self, gd0, kin0, dtype=float, block=1):
        gd1 = gd0.coarsen()
        gd2 = gd1.coarsen()
        self.kin0 = kin0
        self.kin1 = Laplace(gd1, -0.5, 1, dtype)
        self.kin2 = Laplace(gd2, -0.5, 1, dtype)
        self.scratch0 = gd0.zeros((2, block), dtype, False)
        self.scratch1 = gd1.zeros((3, block), dtype, False)
        self.scratch2 = gd2.zeros((3, block), dtype, False)
        self.step = 0.66666666 / kin0.get_diagonal_element()

        self.restrictor_object0 = Transformer(gd0, gd1, 1, dtype)
        self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype)
        self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype)
        self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype)
        self.restrictor0 = self.restrictor_object0.apply
        self.restrictor1 = self.restrictor_object1.apply
        self.interpolator2 = self.interpolator_object2.apply
        self.interpolator1 = self.interpolator_object1.apply
Beispiel #14
0
    def __init__(self, gd, bd, kd, setups, dtype):  # override constructor

        assert kd.comm.size == 1

        WaveFunctions.__init__(self, gd, 1, setups, bd, dtype, world, kd, None)
        self.kin = Laplace(gd, -0.5, dtype=dtype, allocate=False)
        self.diagksl = None
        self.orthoksl = BandLayouts(gd, bd, dtype)
        self.initksl = None
        self.overlap = None
        self.rank_a = None
Beispiel #15
0
class Preconditioner:
    def __init__(self, gd0, kin0, dtype=float, block=1):
        gd1 = gd0.coarsen()
        gd2 = gd1.coarsen()
        self.kin0 = kin0
        self.kin1 = Laplace(gd1, -0.5, 1, dtype)
        self.kin2 = Laplace(gd2, -0.5, 1, dtype)
        self.scratch0 = gd0.zeros((2, block), dtype, False)
        self.scratch1 = gd1.zeros((3, block), dtype, False)
        self.scratch2 = gd2.zeros((3, block), dtype, False)
        self.step = 0.66666666 / kin0.get_diagonal_element()

        self.restrictor_object0 = Transformer(gd0, gd1, 1, dtype)
        self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype)
        self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype)
        self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype)
        self.restrictor0 = self.restrictor_object0.apply
        self.restrictor1 = self.restrictor_object1.apply
        self.interpolator2 = self.interpolator_object2.apply
        self.interpolator1 = self.interpolator_object1.apply

    def calculate_kinetic_energy(self, psit_xG, kpt):
        return None

    def __call__(self, residuals, kpt, ekin=None, out=None):
        if residuals.ndim == 3:
            if out is None:
                return self.__call__(residuals[np.newaxis], kpt)[0]
            return self.__call__(residuals[np.newaxis], kpt,
                                 out=out[np.newaxis])[0]
        nb = len(residuals)  # number of bands
        phases = kpt.phase_cd
        step = self.step
        if out is None:
            d0, q0 = self.scratch0[:, :nb]
        else:
            d0 = out
            q0 = self.scratch0[0, :nb]
        r1, d1, q1 = self.scratch1[:, :nb]
        r2, d2, q2 = self.scratch2[:, :nb]
        self.restrictor0(-residuals, r1, phases)
        d1[:] = 4 * step * r1
        self.kin1.apply(d1, q1, phases)
        q1 -= r1
        self.restrictor1(q1, r2, phases)
        d2 = 16 * step * r2
        self.kin2.apply(d2, q2, phases)
        q2 -= r2
        d2 -= 16 * step * q2
        self.interpolator2(d2, q1, phases)
        d1 -= q1
        self.kin1.apply(d1, q1, phases)
        q1 -= r1
        d1 -= 4 * step * q1
        self.interpolator1(-d1, d0, phases)
        self.kin0.apply(d0, q0, phases)
        q0 -= residuals
        axpy(-step, q0, d0)  # d0 -= step * q0
        d0 *= -1.0
        return d0
Beispiel #16
0
Datei: fd.py Projekt: qsnake/gpaw
    def __init__(self, stencil, diagksl, orthoksl, initksl,
                 gd, nvalence, setups, bd,
                 dtype, world, kd, timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl,
                                   gd, nvalence, setups, bd,
                                   dtype, world, kd, timer)

        self.wd = self.gd  # wave function descriptor
        
        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype, allocate=False)

        self.matrixoperator = MatrixOperator(orthoksl)
Beispiel #17
0
    def __init__(self, stencil, diagksl, orthoksl, initksl,
                 gd, nvalence, setups, bd,
                 dtype, world, kd, timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl,
                                   gd, nvalence, setups, bd,
                                   dtype, world, kd, timer)

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype)

        self.matrixoperator = MatrixOperator(self.orthoksl)

        self.taugrad_v = None  # initialized by MGGA functional
Beispiel #18
0
class Preconditioner:
    def __init__(self, gd0, kin0, dtype=float, block=1):
        gd1 = gd0.coarsen()
        gd2 = gd1.coarsen()
        self.kin0 = kin0
        self.kin1 = Laplace(gd1, -0.5, 1, dtype)
        self.kin2 = Laplace(gd2, -0.5, 1, dtype)
        self.scratch0 = gd0.zeros((2, block), dtype, False)
        self.scratch1 = gd1.zeros((3, block), dtype, False)
        self.scratch2 = gd2.zeros((3, block), dtype, False)
        self.step = 0.66666666 / kin0.get_diagonal_element()

        self.restrictor_object0 = Transformer(gd0, gd1, 1, dtype, False)
        self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype, False)
        self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype, False)
        self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype, False)
        self.restrictor0 = self.restrictor_object0.apply
        self.restrictor1 = self.restrictor_object1.apply
        self.interpolator2 = self.interpolator_object2.apply
        self.interpolator1 = self.interpolator_object1.apply
        self.allocated = False

    def allocate(self):
        assert not self.allocated
        for transformer in [
                self.restrictor_object0, self.restrictor_object1,
                self.interpolator_object2, self.interpolator_object1
        ]:
            transformer.allocate()
        self.allocated = True

    def __call__(self, residuals, kpt):
        nb = len(residuals)  # number of bands
        phases = kpt.phase_cd
        step = self.step
        d0, q0 = self.scratch0[:, :nb]
        r1, d1, q1 = self.scratch1[:, :nb]
        r2, d2, q2 = self.scratch2[:, :nb]
        self.restrictor0(-residuals, r1, phases)
        d1[:] = 4 * step * r1
        self.kin1.apply(d1, q1, phases)
        q1 -= r1
        self.restrictor1(q1, r2, phases)
        d2 = 16 * step * r2
        self.kin2.apply(d2, q2, phases)
        q2 -= r2
        d2 -= 16 * step * q2
        self.interpolator2(d2, q1, phases)
        d1 -= q1
        self.kin1.apply(d1, q1, phases)
        q1 -= r1
        d1 -= 4 * step * q1
        self.interpolator1(-d1, d0, phases)
        self.kin0.apply(d0, q0, phases)
        q0 -= residuals
        axpy(-step, q0, d0)  # d0 -= step * q0
        d0 *= -1.0
        return d0
Beispiel #19
0
class Preconditioner:
    def __init__(self, gd0, kin0, dtype=float, block=1):
        gd1 = gd0.coarsen()
        gd2 = gd1.coarsen()
        self.kin0 = kin0
        self.kin1 = Laplace(gd1, -0.5, 1, dtype)
        self.kin2 = Laplace(gd2, -0.5, 1, dtype)
        self.scratch0 = gd0.zeros((2, block), dtype, False)
        self.scratch1 = gd1.zeros((3, block),dtype, False)
        self.scratch2 = gd2.zeros((3, block), dtype, False)
        self.step = 0.66666666 / kin0.get_diagonal_element()

        self.restrictor_object0 = Transformer(gd0, gd1, 1,dtype, False)
        self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype, False)
        self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype, False)
        self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype, False)
        self.restrictor0 = self.restrictor_object0.apply
        self.restrictor1 = self.restrictor_object1.apply
        self.interpolator2 = self.interpolator_object2.apply
        self.interpolator1 = self.interpolator_object1.apply
        self.allocated = False

    def allocate(self):
        assert not self.allocated
        for transformer in [self.restrictor_object0,
                            self.restrictor_object1,
                            self.interpolator_object2,
                            self.interpolator_object1]:
            transformer.allocate()
        self.allocated = True
        
    def __call__(self, residuals, kpt):
        nb = len(residuals) # number of bands
        phases = kpt.phase_cd
        step = self.step
        d0, q0 = self.scratch0[:,:nb]
        r1, d1, q1 = self.scratch1[:, :nb]
        r2, d2, q2 = self.scratch2[:, :nb]
        self.restrictor0(-residuals, r1, phases)
        d1[:] = 4 * step * r1
        self.kin1.apply(d1, q1, phases)
        q1 -= r1
        self.restrictor1(q1, r2, phases)
        d2 = 16 * step * r2
        self.kin2.apply(d2, q2, phases)
        q2 -= r2
        d2 -= 16 * step * q2
        self.interpolator2(d2, q1, phases)
        d1 -= q1
        self.kin1.apply(d1, q1, phases)
        q1 -= r1
        d1 -= 4 * step * q1
        self.interpolator1(-d1, d0, phases)
        self.kin0.apply(d0, q0, phases)
        q0 -= residuals
        axpy(-step, q0, d0)  # d0 -= step * q0
        d0 *= -1.0
        return d0
Beispiel #20
0
    def __init__(self,
                 stencil,
                 diagksl,
                 orthoksl,
                 initksl,
                 gd,
                 nvalence,
                 setups,
                 bd,
                 dtype,
                 world,
                 kd,
                 timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd,
                                   nvalence, setups, bd, dtype, world, kd,
                                   timer)

        self.wd = self.gd  # wave function descriptor

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype, allocate=False)

        self.matrixoperator = MatrixOperator(orthoksl)
Beispiel #21
0
    def set_absorbing_boundary(self, absorbing_boundary):
        """ Sets up the absorbing boundary.            
            Parameters:
            absorbing_boundary: absorbing boundary object of any kind.  
        """

        self.absorbing_boundary = absorbing_boundary
        self.absorbing_boundary.set_up(self.hamiltonian.gd)
        if self.absorbing_boundary.type == 'PML':
            gd = self.hamiltonian.gd
            self.laplace = Laplace(gd, n=2, dtype=complex)
            self.gradient = np.array(
                (Gradient(gd, 0, n=2,
                          dtype=complex), Gradient(gd, 1, n=2, dtype=complex),
                 Gradient(gd, 2, n=2, dtype=complex)))
            self.lpsit = None
Beispiel #22
0
 def initialize(self, load_gauss=False):
     self.presmooths[self.levels] = 8
     self.postsmooths[self.levels] = 8
     self.phis = [None] + [gd.zeros() for gd in self.gds[1:]]
     self.residuals = [gd.zeros() for gd in self.gds]
     self.rhos = [gd.zeros() for gd in self.gds]
     self.op_coarse_weights = [[g.empty() for g in (gd, ) * 4]
                               for gd in self.gds[1:]]
     scale = -0.25 / np.pi
     for i, gd in enumerate(self.gds):
         if i == 0:
             nn = self.nn
             weights = self.dielectric.eps_gradeps
         else:
             nn = 1
             weights = self.op_coarse_weights[i - 1]
         operators = [Laplace(gd, scale, nn)] + \
                     [Gradient(gd, j, scale, nn) for j in (0, 1, 2)]
         self.operators.append(WeightedFDOperator(weights, operators))
     if load_gauss:
         self.load_gauss()
Beispiel #23
0
    def __init__(self, gd, project, dtype=float):
        """Init the gpaw preconditioner.

        Parameters
        ----------
        gd: GridDescriptor
            Coarse grid
            
        """

        self.project = project
        self.gd = gd
        # K-point for the preconditioner
        self.kpt = None
        
        kin = Laplace(gd, scale=-0.5, n=3, dtype=dtype)
        self.pc = Preconditioner(gd, kin, dtype=dtype)
        
        # For scipy's linear solver
        N = np.prod(gd.n_c)
        self.shape = (N,N)
        self.dtype = dtype
Beispiel #24
0
    def create_laplace(self, gd, scale=1.0, n=1, dtype=float):
        """Instantiate and return a Laplace operator

        Allows subclasses to change the Laplace operator
        """
        return Laplace(gd, scale, n, dtype)
Beispiel #25
0
 def create_laplace(self, gd, scale=1.0, n=1, dtype=float):
     operators = [Laplace(gd, scale, n, dtype)]
     operators += [Gradient(gd, j, scale, n, dtype) for j in (0, 1, 2)]
     return WeightedFDOperator(operators)
Beispiel #26
0
 def initialize(self, dens, ham, wfs, occ):
     MGGA.initialize(self, dens, ham, wfs, occ)
     self.kernel.world = wfs.world
     self.kernel.gd = dens.finegd
     self.kernel.lapl = Laplace(dens.finegd)
Beispiel #27
0
from time import time
from gpaw.grid_descriptor import GridDescriptor
from gpaw.fd_operators import Laplace
import gpaw.mpi as mpi

n = 96
h = 0.1
L = n * h
gd = GridDescriptor((n, n, n), [L, L, L])

# Allocate arrays:
a = gd.zeros(100) + 1.2
b = gd.empty(100)

o = Laplace(gd, 2).apply

t0 = time()
for r in range(10):
    o(a, b)

if mpi.rank == 0:
    print time() - t0, a.shape
    
Beispiel #28
0
offload_enabled = os.environ.get("GPAW_OFFLOAD");

device = mic.devices[0]

gpts = 64
gd = GridDescriptor([gpts, gpts, gpts])

a = gd.empty() # source
b = gd.empty() # result

np.random.seed(10)
a[:] = np.random.random(a.shape)
b[:] = np.zeros(b.shape)

op = Laplace(gd, 1.0, 3)

if offload_enabled:
    offl_a = device.bind(a)
    offl_b = device.bind(b)

print "--------------------------------------------------------------"
print "Starting relaxation step"
relax_start = time.time()
if offload_enabled:
    op.relax(2, offl_b.array, offl_a.array, 4, 2.0 / 3.0)
else:
    op.relax(2, b, a, 4, 2.0 / 3.0)
relax_end = time.time()
print "--------------------------------------------------------------"
class SternheimerOperator:
    """Class implementing the linear operator in the Sternheimer equation.
    
    The main purpose of this class is to implement the multiplication of the
    linear operator (H - eps_nk) with a vector in the ``apply`` member
    function. An additional ``matvec`` member function has been defined so that
    instances of this class can be passed as a linear operator to scipy's
    iterative Krylov solvers in ``scipy.sparse.linalg``.

    """
    
    def __init__(self, hamiltonian, wfs, gd, dtype=float):
        """Save useful objects for the Sternheimer operator.

        Parameters
        ----------
        hamiltonian: Hamiltonian
            Hamiltonian for a ground-state calculation.
        wfs: WaveFunctions
            Ground-state wave-functions.
        gd: GridDescriptor
            Grid on which the operator is defined.
        dtype: dtype
            dtype of the wave-function being operated on.

        """

        self.hamiltonian = hamiltonian
        self.kin = Laplace(gd, scale=-0.5, n=3, dtype=dtype)
        self.kpt_u = wfs.kpt_u
        self.pt = wfs.pt
        self.gd = gd

        # Variables for k-point and band index
        self.k = None
        self.n = None
        self.kplusq = None
        
        # For scipy's linear solver
        N = np.prod(gd.n_c)
        self.shape = (N, N)
        self.dtype = dtype

    def set_k(self, k):
        """Set k-vector for the Bloch-state in consideration."""

        self.k = k
        
    def set_band(self, n):
        """Set band index for the Bloch-state in consideration.

        Note that n different from None has implications for the interpretation
        of the input vector in the ``apply`` member function.

        """

        self.n = n

    def set_kplusq(self, kplusq):
        """Set q-vector of the perturbing potential.

        Parameters
        ----------
        kplusq: int
           Index of the k+q vector.

        """

        self.kplusq = kplusq

    def apply(self, x_nG, y_nG):
        """Apply the linear operator in the Sternheimer equation to a vector.

        For the eigenvalue term the k-point is the one of the state.
        For the other terms the k-point to be used is the one given by the k+q
        phase of the first-order of the state. Only for q=0 do the two coincide.
        
        Parameters
        ----------
        x_nG: ndarray
            Vector(s) to which the Sternheimer operator is applied.
        y_nG: ndarray
            Resulting vector(s).
            
        """

        assert x_nG.ndim in (3, 4)
        assert x_nG.shape == y_nG.shape
        assert tuple(self.gd.n_c) == x_nG.shape[-3:]
        assert self.k is not None

        # k
        kpt = self.kpt_u[self.k]
        # k+q
        kplusqpt = self.kpt_u[self.kplusq]
        
        # Kintetic energy
        # k+q
        self.kin.apply(x_nG, y_nG, phase_cd=kplusqpt.phase_cd)

        # Local part of effective potential - no phase !!
        self.hamiltonian.apply_local_potential(x_nG, y_nG, kpt.s)
        
        # Non-local part from projectors (coefficients can not be reused)
        shape = x_nG.shape[:-3]
        P_ani = self.pt.dict(shape=shape)

        # k+q 
        self.pt.integrate(x_nG, P_ani, q=kplusqpt.k)

        for a, P_ni in P_ani.items():
            dH_ii = unpack(self.hamiltonian.dH_asp[a][kpt.s])
            P_ani[a] = np.dot(P_ni, dH_ii)
        # k+q
        self.pt.add(y_nG, P_ani, q=kplusqpt.k)

        # XXX Eigenvalue term
        if self.n is not None:
            # k
            y_nG -= kpt.eps_n[self.n] * x_nG
        else:
            for n, x_G in enumerate(x_nG):
                # k
                y_nG[n] -= kpt.eps_n[n] * x_G

        # Project out undesired (numerical) components
        # k+q
        self.project(y_nG)

    def project(self, x_nG):
        """Project the vector onto the unoccupied states at k+q.

        The projection operator is defined as follows::

                      --                    --             
             P      = >  |Psi ><Psi | = 1 - >  |Psi ><Psi |
              c,k+q   --     c     c        --     v     v 
                       c    k+q   k+q        v    k+q   k+q
        
        """

        # It might be a good idea to move this functionality to its own class
        assert x_nG.ndim == 4
        assert self.kplusq is not None

        # k+q
        kplusqpt = self.kpt_u[self.kplusq]
        # Occupied wave function
        psit_nG = kplusqpt.psit_nG

        # Project out occupied sub-space using blas routine gemm
        m = len(x_nG)
        n = len(psit_nG)
        proj_mn = np.zeros((m, n), dtype=self.dtype)
        gemm(self.gd.dv, psit_nG, x_nG, 0.0, proj_mn, 'c')
        gemm(-1.0, psit_nG, proj_mn, 1.0, x_nG)

        # Project out one orbital at a time
        ## for n, psit_G in enumerate(psit_nG):
        ## 
        ##     proj = self.gd.integrate(psit_G.conjugate() * x_nG)
        ##     x_nG -= proj * psit_G
        
    def matvec(self, x):
        """Matrix-vector multiplication for scipy's Krylov solvers.

        This is a wrapper around the ``apply`` member function above. It allows
        to multiply the sternheimer operator onto the 1-dimensional scipy
        representation of a gpaw grid vector(s).
        
        Parameters
        ----------
        a: ndarray
            1-dimensional array holding the representation of a gpaw grid
            vector (possibly a set of vectors).

        """

        # Check that a is 1-dimensional
        assert len(x.shape) == 1
        
        # Find the number of states in x
        grid_shape = tuple(self.gd.n_c)
        assert ((x.size % np.prod(grid_shape)) == 0), ("Incompatible array " +
                                                       "shapes")
        # Number of states in the vector
        N = x.size / np.prod(grid_shape)
        
        # Output array
        y_nG = self.gd.zeros(n=N, dtype=self.dtype)
        shape = y_nG.shape

        assert x.size == np.prod(y_nG.shape)
        
        x_nG = x.reshape(shape)

        self.apply(x_nG, y_nG)
        
        y = y_nG.ravel()
        
        return y
Beispiel #30
0
class FDWaveFunctions(FDPWWaveFunctions):
    def __init__(self,
                 stencil,
                 diagksl,
                 orthoksl,
                 initksl,
                 gd,
                 nvalence,
                 setups,
                 bd,
                 dtype,
                 world,
                 kd,
                 timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd,
                                   nvalence, setups, bd, dtype, world, kd,
                                   timer)

        self.wd = self.gd  # wave function descriptor

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype, allocate=False)

        self.matrixoperator = MatrixOperator(orthoksl)

    def set_setups(self, setups):
        self.pt = LFC(self.gd, [setup.pt_j for setup in setups],
                      self.kpt_comm,
                      dtype=self.dtype,
                      forces=True)
        FDPWWaveFunctions.set_setups(self, setups)

    def set_positions(self, spos_ac):
        if not self.kin.is_allocated():
            self.kin.allocate()
        FDPWWaveFunctions.set_positions(self, spos_ac)

    def summary(self, fd):
        fd.write('Mode: Finite-difference\n')

    def make_preconditioner(self, block=1):
        return Preconditioner(self.gd, self.kin, self.dtype, block)

    def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG):
        self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd)
        hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s)

    def add_orbital_density(self, nt_G, kpt, n):
        if self.dtype == float:
            axpy(1.0, kpt.psit_nG[n]**2, nt_G)
        else:
            axpy(1.0, kpt.psit_nG[n].real**2, nt_G)
            axpy(1.0, kpt.psit_nG[n].imag**2, nt_G)

    def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n):
        # Used in calculation of response part of GLLB-potential
        nt_G = nt_sG[kpt.s]
        if self.dtype == float:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G**2, nt_G)
        else:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G.real**2, nt_G)
                axpy(f, psit_G.imag**2, nt_G)

        # Hack used in delta-scf calculations:
        if hasattr(kpt, 'c_on'):
            assert self.bd.comm.size == 1
            d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands),
                            dtype=complex)
            for ne, c_n in zip(kpt.ne_o, kpt.c_on):
                d_nn += ne * np.outer(c_n.conj(), c_n)
            for d_n, psi0_G in zip(d_nn, kpt.psit_nG):
                for d, psi_G in zip(d_n, kpt.psit_nG):
                    if abs(d) > 1.e-12:
                        nt_G += (psi0_G.conj() * d * psi_G).real

    def calculate_kinetic_energy_density(self, tauct, grad_v):
        assert not hasattr(self.kpt_u[0], 'c_on')
        if isinstance(self.kpt_u[0].psit_nG, TarFileReference):
            raise RuntimeError('Wavefunctions have not been initialized.')

        taut_sG = self.gd.zeros(self.nspins)
        dpsit_G = self.gd.empty(dtype=self.dtype)
        for kpt in self.kpt_u:
            for f, psit_G in zip(kpt.f_n, kpt.psit_nG):
                for v in range(3):
                    grad_v[v](psit_G, dpsit_G, kpt.phase_cd)
                    axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s])

        self.kpt_comm.sum(taut_sG)
        self.band_comm.sum(taut_sG)
        return taut_sG

    def calculate_forces(self, hamiltonian, F_av):
        # Calculate force-contribution from k-points:
        F_av.fill(0.0)
        F_aniv = self.pt.dict(self.bd.mynbands, derivative=True)
        for kpt in self.kpt_u:
            self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q)
            for a, F_niv in F_aniv.items():
                F_niv = F_niv.conj()
                F_niv *= kpt.f_n[:, np.newaxis, np.newaxis]
                dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s])
                P_ni = kpt.P_ani[a]
                F_vii = np.dot(np.dot(F_niv.transpose(), P_ni), dH_ii)
                F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis]
                dO_ii = hamiltonian.setups[a].dO_ii
                F_vii -= np.dot(np.dot(F_niv.transpose(), P_ni), dO_ii)
                F_av[a] += 2 * F_vii.real.trace(0, 1, 2)

            # Hack used in delta-scf calculations:
            if hasattr(kpt, 'c_on'):
                assert self.bd.comm.size == 1
                self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q)  #XXX again
                d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands),
                                dtype=complex)
                for ne, c_n in zip(kpt.ne_o, kpt.c_on):
                    d_nn += ne * np.outer(c_n.conj(), c_n)
                for a, F_niv in F_aniv.items():
                    F_niv = F_niv.conj()
                    dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s])
                    Q_ni = np.dot(d_nn, kpt.P_ani[a])
                    F_vii = np.dot(np.dot(F_niv.transpose(), Q_ni), dH_ii)
                    F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis]
                    dO_ii = hamiltonian.setups[a].dO_ii
                    F_vii -= np.dot(np.dot(F_niv.transpose(), Q_ni), dO_ii)
                    F_av[a] += 2 * F_vii.real.trace(0, 1, 2)

        self.bd.comm.sum(F_av, 0)

        if self.bd.comm.rank == 0:
            self.kpt_comm.sum(F_av, 0)

    def estimate_memory(self, mem):
        FDPWWaveFunctions.estimate_memory(self, mem)
        self.kin.estimate_memory(mem.subnode('Kinetic operator'))
Beispiel #31
0
class FDWaveFunctions(FDPWWaveFunctions):
    mode = 'fd'

    def __init__(self,
                 stencil,
                 diagksl,
                 orthoksl,
                 initksl,
                 gd,
                 nvalence,
                 setups,
                 bd,
                 dtype,
                 world,
                 kd,
                 kptband_comm,
                 timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd,
                                   nvalence, setups, bd, dtype, world, kd,
                                   kptband_comm, timer)

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype)

        self.matrixoperator = MatrixOperator(self.orthoksl)

        self.taugrad_v = None  # initialized by MGGA functional

    def empty(self, n=(), global_array=False, realspace=False, q=-1):
        return self.gd.empty(n, self.dtype, global_array)

    def integrate(self, a_xg, b_yg=None, global_integral=True):
        return self.gd.integrate(a_xg, b_yg, global_integral)

    def bytes_per_wave_function(self):
        return self.gd.bytecount(self.dtype)

    def set_setups(self, setups):
        self.pt = LFC(self.gd, [setup.pt_j for setup in setups],
                      self.kd,
                      dtype=self.dtype,
                      forces=True)
        FDPWWaveFunctions.set_setups(self, setups)

    def set_positions(self, spos_ac):
        FDPWWaveFunctions.set_positions(self, spos_ac)

    def summary(self, fd):
        fd.write('Wave functions: Uniform real-space grid\n')
        fd.write('Kinetic energy operator: %s\n' % self.kin.description)

    def make_preconditioner(self, block=1):
        return Preconditioner(self.gd, self.kin, self.dtype, block)

    def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG):
        self.timer.start('Apply hamiltonian')
        self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd)
        hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s)
        self.timer.stop('Apply hamiltonian')

    def add_orbital_density(self, nt_G, kpt, n):
        if self.dtype == float:
            axpy(1.0, kpt.psit_nG[n]**2, nt_G)
        else:
            axpy(1.0, kpt.psit_nG[n].real**2, nt_G)
            axpy(1.0, kpt.psit_nG[n].imag**2, nt_G)

    def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n):
        # Used in calculation of response part of GLLB-potential
        nt_G = nt_sG[kpt.s]
        if self.dtype == float:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G**2, nt_G)
        else:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G.real**2, nt_G)
                axpy(f, psit_G.imag**2, nt_G)

        # Hack used in delta-scf calculations:
        if hasattr(kpt, 'c_on'):
            assert self.bd.comm.size == 1
            d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands),
                            dtype=complex)
            for ne, c_n in zip(kpt.ne_o, kpt.c_on):
                d_nn += ne * np.outer(c_n.conj(), c_n)
            for d_n, psi0_G in zip(d_nn, kpt.psit_nG):
                for d, psi_G in zip(d_n, kpt.psit_nG):
                    if abs(d) > 1.e-12:
                        nt_G += (psi0_G.conj() * d * psi_G).real

    def calculate_kinetic_energy_density(self):
        if self.taugrad_v is None:
            self.taugrad_v = [
                Gradient(self.gd, v, n=3, dtype=self.dtype).apply
                for v in range(3)
            ]

        assert not hasattr(self.kpt_u[0], 'c_on')
        if self.kpt_u[0].psit_nG is None:
            raise RuntimeError('No wavefunctions yet')
        if isinstance(self.kpt_u[0].psit_nG, FileReference):
            # XXX initialize
            raise RuntimeError('Wavefunctions have not been initialized.')

        taut_sG = self.gd.zeros(self.nspins)
        dpsit_G = self.gd.empty(dtype=self.dtype)
        for kpt in self.kpt_u:
            for f, psit_G in zip(kpt.f_n, kpt.psit_nG):
                for v in range(3):
                    self.taugrad_v[v](psit_G, dpsit_G, kpt.phase_cd)
                    axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s])

        self.kd.comm.sum(taut_sG)
        self.band_comm.sum(taut_sG)
        return taut_sG

    def apply_mgga_orbital_dependent_hamiltonian(self, kpt, psit_xG, Htpsit_xG,
                                                 dH_asp, dedtaut_G):
        a_G = self.gd.empty(dtype=psit_xG.dtype)
        for psit_G, Htpsit_G in zip(psit_xG, Htpsit_xG):
            for v in range(3):
                self.taugrad_v[v](psit_G, a_G, kpt.phase_cd)
                self.taugrad_v[v](dedtaut_G * a_G, a_G, kpt.phase_cd)
                axpy(-0.5, a_G, Htpsit_G)

    def ibz2bz(self, atoms):
        """Transform wave functions in IBZ to the full BZ."""

        assert self.kd.comm.size == 1

        # New k-point descriptor for full BZ:
        kd = KPointDescriptor(self.kd.bzk_kc, nspins=self.nspins)
        #kd.set_symmetry(atoms, self.setups, enabled=False)
        kd.set_communicator(serial_comm)

        self.pt = LFC(self.gd, [setup.pt_j for setup in self.setups],
                      kd,
                      dtype=self.dtype)
        self.pt.set_positions(atoms.get_scaled_positions())

        self.initialize_wave_functions_from_restart_file()

        weight = 2.0 / kd.nspins / kd.nbzkpts

        # Build new list of k-points:
        kpt_u = []
        for s in range(self.nspins):
            for k in range(kd.nbzkpts):
                # Index of symmetry related point in the IBZ
                ik = self.kd.bz2ibz_k[k]
                r, u = self.kd.get_rank_and_index(s, ik)
                assert r == 0
                kpt = self.kpt_u[u]

                phase_cd = np.exp(2j * np.pi * self.gd.sdisp_cd *
                                  kd.bzk_kc[k, :, np.newaxis])

                # New k-point:
                kpt2 = KPoint(weight, s, k, k, phase_cd)
                kpt2.f_n = kpt.f_n / kpt.weight / kd.nbzkpts * 2 / self.nspins
                kpt2.eps_n = kpt.eps_n.copy()

                # Transform wave functions using symmetry operation:
                Psit_nG = self.gd.collect(kpt.psit_nG)
                if Psit_nG is not None:
                    Psit_nG = Psit_nG.copy()
                    for Psit_G in Psit_nG:
                        Psit_G[:] = self.kd.transform_wave_function(Psit_G, k)
                kpt2.psit_nG = self.gd.empty(self.bd.nbands, dtype=self.dtype)
                self.gd.distribute(Psit_nG, kpt2.psit_nG)

                # Calculate PAW projections:
                kpt2.P_ani = self.pt.dict(len(kpt.psit_nG))
                self.pt.integrate(kpt2.psit_nG, kpt2.P_ani, k)

                kpt_u.append(kpt2)

        self.kd = kd
        self.kpt_u = kpt_u

    def write(self, writer, write_wave_functions=False):
        writer['Mode'] = 'fd'

        if not write_wave_functions:
            return

        writer.add(
            'PseudoWaveFunctions',
            ('nspins', 'nibzkpts', 'nbands', 'ngptsx', 'ngptsy', 'ngptsz'),
            dtype=self.dtype)

        if hasattr(writer, 'hdf5'):
            parallel = (self.world.size > 1)
            for kpt in self.kpt_u:
                indices = [kpt.s, kpt.k]
                indices.append(self.bd.get_slice())
                indices += self.gd.get_slice()
                writer.fill(kpt.psit_nG, parallel=parallel, *indices)
        else:
            for s in range(self.nspins):
                for k in range(self.kd.nibzkpts):
                    for n in range(self.bd.nbands):
                        psit_G = self.get_wave_function_array(n, k, s)
                        writer.fill(psit_G, s, k, n)

    def read(self, reader, hdf5):
        if ((not hdf5 and self.bd.comm.size == 1)
                or (hdf5 and self.world.size == 1)):
            # We may not be able to keep all the wave
            # functions in memory - so psit_nG will be a special type of
            # array that is really just a reference to a file:
            for kpt in self.kpt_u:
                kpt.psit_nG = reader.get_reference('PseudoWaveFunctions',
                                                   (kpt.s, kpt.k))
        else:
            for kpt in self.kpt_u:
                kpt.psit_nG = self.empty(self.bd.mynbands)
                if hdf5:
                    indices = [kpt.s, kpt.k]
                    indices.append(self.bd.get_slice())
                    indices += self.gd.get_slice()
                    reader.get('PseudoWaveFunctions',
                               out=kpt.psit_nG,
                               parallel=(self.world.size > 1),
                               *indices)
                else:
                    # Read band by band to save memory
                    for myn, psit_G in enumerate(kpt.psit_nG):
                        n = self.bd.global_index(myn)
                        if self.gd.comm.rank == 0:
                            big_psit_G = np.array(
                                reader.get('PseudoWaveFunctions', kpt.s, kpt.k,
                                           n), self.dtype)
                        else:
                            big_psit_G = None
                        self.gd.distribute(big_psit_G, psit_G)

    def initialize_from_lcao_coefficients(self, basis_functions, mynbands):
        for kpt in self.kpt_u:
            kpt.psit_nG = self.gd.zeros(self.bd.mynbands, self.dtype)
            basis_functions.lcao_to_grid(kpt.C_nM, kpt.psit_nG[:mynbands],
                                         kpt.q)
            kpt.C_nM = None
            if use_mic:
                kpt.psit_nG_mic = stream.bind(kpt.psit_nG)
                stream.sync()

    def random_wave_functions(self, nao):
        """Generate random wave functions."""

        gpts = self.gd.N_c[0] * self.gd.N_c[1] * self.gd.N_c[2]

        if self.bd.nbands < gpts / 64:
            gd1 = self.gd.coarsen()
            gd2 = gd1.coarsen()

            psit_G1 = gd1.empty(dtype=self.dtype)
            psit_G2 = gd2.empty(dtype=self.dtype)

            interpolate2 = Transformer(gd2, gd1, 1, self.dtype).apply
            interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply

            shape = tuple(gd2.n_c)
            scale = np.sqrt(12 / abs(np.linalg.det(gd2.cell_cv)))

            old_state = np.random.get_state()

            np.random.seed(4 + self.world.rank)

            for kpt in self.kpt_u:
                for psit_G in kpt.psit_nG[nao:]:
                    if self.dtype == float:
                        psit_G2[:] = (np.random.random(shape) - 0.5) * scale
                    else:
                        psit_G2.real = (np.random.random(shape) - 0.5) * scale
                        psit_G2.imag = (np.random.random(shape) - 0.5) * scale

                    interpolate2(psit_G2, psit_G1, kpt.phase_cd)
                    interpolate1(psit_G1, psit_G, kpt.phase_cd)
            np.random.set_state(old_state)

        elif gpts / 64 <= self.bd.nbands < gpts / 8:
            gd1 = self.gd.coarsen()

            psit_G1 = gd1.empty(dtype=self.dtype)

            interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply

            shape = tuple(gd1.n_c)
            scale = np.sqrt(12 / abs(np.linalg.det(gd1.cell_cv)))

            old_state = np.random.get_state()

            np.random.seed(4 + self.world.rank)

            for kpt in self.kpt_u:
                for psit_G in kpt.psit_nG[nao:]:
                    if self.dtype == float:
                        psit_G1[:] = (np.random.random(shape) - 0.5) * scale
                    else:
                        psit_G1.real = (np.random.random(shape) - 0.5) * scale
                        psit_G1.imag = (np.random.random(shape) - 0.5) * scale

                    interpolate1(psit_G1, psit_G, kpt.phase_cd)
            np.random.set_state(old_state)

        else:
            shape = tuple(self.gd.n_c)
            scale = np.sqrt(12 / abs(np.linalg.det(self.gd.cell_cv)))

            old_state = np.random.get_state()

            np.random.seed(4 + self.world.rank)

            for kpt in self.kpt_u:
                for psit_G in kpt.psit_nG[nao:]:
                    if self.dtype == float:
                        psit_G[:] = (np.random.random(shape) - 0.5) * scale
                    else:
                        psit_G.real = (np.random.random(shape) - 0.5) * scale
                        psit_G.imag = (np.random.random(shape) - 0.5) * scale

            np.random.set_state(old_state)

    def estimate_memory(self, mem):
        FDPWWaveFunctions.estimate_memory(self, mem)
Beispiel #32
0
Datei: fd.py Projekt: qsnake/gpaw
class FDWaveFunctions(FDPWWaveFunctions):
    def __init__(self, stencil, diagksl, orthoksl, initksl,
                 gd, nvalence, setups, bd,
                 dtype, world, kd, timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl,
                                   gd, nvalence, setups, bd,
                                   dtype, world, kd, timer)

        self.wd = self.gd  # wave function descriptor
        
        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype, allocate=False)

        self.matrixoperator = MatrixOperator(orthoksl)

    def set_setups(self, setups):
        self.pt = LFC(self.gd, [setup.pt_j for setup in setups],
                      self.kpt_comm, dtype=self.dtype, forces=True)
        FDPWWaveFunctions.set_setups(self, setups)

    def set_positions(self, spos_ac):
        if not self.kin.is_allocated():
            self.kin.allocate()
        FDPWWaveFunctions.set_positions(self, spos_ac)

    def summary(self, fd):
        fd.write('Mode: Finite-difference\n')
        
    def make_preconditioner(self, block=1):
        return Preconditioner(self.gd, self.kin, self.dtype, block)
    
    def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG):
        self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd)
        hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s)

    def add_orbital_density(self, nt_G, kpt, n):
        if self.dtype == float:
            axpy(1.0, kpt.psit_nG[n]**2, nt_G)
        else:
            axpy(1.0, kpt.psit_nG[n].real**2, nt_G)
            axpy(1.0, kpt.psit_nG[n].imag**2, nt_G)

    def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n):
        # Used in calculation of response part of GLLB-potential
        nt_G = nt_sG[kpt.s]
        if self.dtype == float:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G**2, nt_G)
        else:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G.real**2, nt_G)
                axpy(f, psit_G.imag**2, nt_G)

        # Hack used in delta-scf calculations:
        if hasattr(kpt, 'c_on'):
            assert self.bd.comm.size == 1
            d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands),
                            dtype=complex)
            for ne, c_n in zip(kpt.ne_o, kpt.c_on):
                d_nn += ne * np.outer(c_n.conj(), c_n)
            for d_n, psi0_G in zip(d_nn, kpt.psit_nG):
                for d, psi_G in zip(d_n, kpt.psit_nG):
                    if abs(d) > 1.e-12:
                        nt_G += (psi0_G.conj() * d * psi_G).real

    def calculate_kinetic_energy_density(self, tauct, grad_v):
        assert not hasattr(self.kpt_u[0], 'c_on')
        if isinstance(self.kpt_u[0].psit_nG, TarFileReference):
            raise RuntimeError('Wavefunctions have not been initialized.')

        taut_sG = self.gd.zeros(self.nspins)
        dpsit_G = self.gd.empty(dtype=self.dtype)
        for kpt in self.kpt_u:
            for f, psit_G in zip(kpt.f_n, kpt.psit_nG):
                for v in range(3):
                    grad_v[v](psit_G, dpsit_G, kpt.phase_cd)
                    axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s])

        self.kpt_comm.sum(taut_sG)
        self.band_comm.sum(taut_sG)
        return taut_sG
        
    def calculate_forces(self, hamiltonian, F_av):
        # Calculate force-contribution from k-points:
        F_av.fill(0.0)
        F_aniv = self.pt.dict(self.bd.mynbands, derivative=True)
        for kpt in self.kpt_u:
            self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q)
            for a, F_niv in F_aniv.items():
                F_niv = F_niv.conj()
                F_niv *= kpt.f_n[:, np.newaxis, np.newaxis]
                dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s])
                P_ni = kpt.P_ani[a]
                F_vii = np.dot(np.dot(F_niv.transpose(), P_ni), dH_ii)
                F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis]
                dO_ii = hamiltonian.setups[a].dO_ii
                F_vii -= np.dot(np.dot(F_niv.transpose(), P_ni), dO_ii)
                F_av[a] += 2 * F_vii.real.trace(0, 1, 2)

            # Hack used in delta-scf calculations:
            if hasattr(kpt, 'c_on'):
                assert self.bd.comm.size == 1
                self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) #XXX again
                d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands),
                                dtype=complex)
                for ne, c_n in zip(kpt.ne_o, kpt.c_on):
                    d_nn += ne * np.outer(c_n.conj(), c_n)
                for a, F_niv in F_aniv.items():
                    F_niv = F_niv.conj()
                    dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s])
                    Q_ni = np.dot(d_nn, kpt.P_ani[a])
                    F_vii = np.dot(np.dot(F_niv.transpose(), Q_ni), dH_ii)
                    F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis]
                    dO_ii = hamiltonian.setups[a].dO_ii
                    F_vii -= np.dot(np.dot(F_niv.transpose(), Q_ni), dO_ii)
                    F_av[a] += 2 * F_vii.real.trace(0, 1, 2)

        self.bd.comm.sum(F_av, 0)

        if self.bd.comm.rank == 0:
            self.kpt_comm.sum(F_av, 0)

    def estimate_memory(self, mem):
        FDPWWaveFunctions.estimate_memory(self, mem)
        self.kin.estimate_memory(mem.subnode('Kinetic operator'))
Beispiel #33
0
class FDWaveFunctions(FDPWWaveFunctions):
    def __init__(self, stencil, diagksl, orthoksl, initksl,
                 gd, nvalence, setups, bd,
                 dtype, world, kd, timer=None):
        FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl,
                                   gd, nvalence, setups, bd,
                                   dtype, world, kd, timer)

        # Kinetic energy operator:
        self.kin = Laplace(self.gd, -0.5, stencil, self.dtype)

        self.matrixoperator = MatrixOperator(self.orthoksl)

        self.taugrad_v = None  # initialized by MGGA functional

    def empty(self, n=(), global_array=False, realspace=False, q=-1):
        return self.gd.empty(n, self.dtype, global_array)

    def integrate(self, a_xg, b_yg=None, global_integral=True):
        return self.gd.integrate(a_xg, b_yg, global_integral)

    def bytes_per_wave_function(self):
        return self.gd.bytecount(self.dtype)

    def set_setups(self, setups):
        self.pt = LFC(self.gd, [setup.pt_j for setup in setups],
                      self.kd, dtype=self.dtype, forces=True)
        FDPWWaveFunctions.set_setups(self, setups)

    def set_positions(self, spos_ac):
        FDPWWaveFunctions.set_positions(self, spos_ac)

    def summary(self, fd):
        fd.write('Wave functions: Uniform real-space grid\n')
        fd.write('Kinetic energy operator: %s\n' % self.kin.description)
        
    def make_preconditioner(self, block=1):
        return Preconditioner(self.gd, self.kin, self.dtype, block)
    
    def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG):
        self.timer.start('Apply hamiltonian')
        self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd)
        hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s)
        self.timer.stop('Apply hamiltonian')

    def add_orbital_density(self, nt_G, kpt, n):
        if self.dtype == float:
            axpy(1.0, kpt.psit_nG[n]**2, nt_G)
        else:
            axpy(1.0, kpt.psit_nG[n].real**2, nt_G)
            axpy(1.0, kpt.psit_nG[n].imag**2, nt_G)

    def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n):
        # Used in calculation of response part of GLLB-potential
        nt_G = nt_sG[kpt.s]
        if self.dtype == float:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G**2, nt_G)
        else:
            for f, psit_G in zip(f_n, kpt.psit_nG):
                axpy(f, psit_G.real**2, nt_G)
                axpy(f, psit_G.imag**2, nt_G)

        # Hack used in delta-scf calculations:
        if hasattr(kpt, 'c_on'):
            assert self.bd.comm.size == 1
            d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands),
                            dtype=complex)
            for ne, c_n in zip(kpt.ne_o, kpt.c_on):
                d_nn += ne * np.outer(c_n.conj(), c_n)
            for d_n, psi0_G in zip(d_nn, kpt.psit_nG):
                for d, psi_G in zip(d_n, kpt.psit_nG):
                    if abs(d) > 1.e-12:
                        nt_G += (psi0_G.conj() * d * psi_G).real

    def calculate_kinetic_energy_density(self):
        if self.taugrad_v is None:
            self.taugrad_v = [
                Gradient(self.gd, v, n=3, dtype=self.dtype).apply
                for v in range(3)]
            
        assert not hasattr(self.kpt_u[0], 'c_on')
        if self.kpt_u[0].psit_nG is None:
            raise RuntimeError('No wavefunctions yet')
        if isinstance(self.kpt_u[0].psit_nG, FileReference):
            # XXX initialize
            raise RuntimeError('Wavefunctions have not been initialized.')

        taut_sG = self.gd.zeros(self.nspins)
        dpsit_G = self.gd.empty(dtype=self.dtype)
        for kpt in self.kpt_u:
            for f, psit_G in zip(kpt.f_n, kpt.psit_nG):
                for v in range(3):
                    self.taugrad_v[v](psit_G, dpsit_G, kpt.phase_cd)
                    axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s])

        self.kpt_comm.sum(taut_sG)
        self.band_comm.sum(taut_sG)
        return taut_sG
        
    def apply_mgga_orbital_dependent_hamiltonian(self, kpt, psit_xG,
                                                 Htpsit_xG, dH_asp,
                                                 dedtaut_G):
        a_G = self.gd.empty(dtype=psit_xG.dtype)
        for psit_G, Htpsit_G in zip(psit_xG, Htpsit_xG):
            for v in range(3):
                self.taugrad_v[v](psit_G, a_G, kpt.phase_cd)
                self.taugrad_v[v](dedtaut_G * a_G, a_G, kpt.phase_cd)
                axpy(-0.5, a_G, Htpsit_G)

    def ibz2bz(self, atoms):
        """Transform wave functions in IBZ to the full BZ."""

        assert self.kd.comm.size == 1

        # New k-point descriptor for full BZ:
        kd = KPointDescriptor(self.kd.bzk_kc, nspins=self.nspins)
        kd.set_symmetry(atoms, self.setups, usesymm=None)
        kd.set_communicator(serial_comm)

        self.pt = LFC(self.gd, [setup.pt_j for setup in self.setups],
                      kd, dtype=self.dtype)
        self.pt.set_positions(atoms.get_scaled_positions())

        self.initialize_wave_functions_from_restart_file()

        weight = 2.0 / kd.nspins / kd.nbzkpts
        
        # Build new list of k-points:
        kpt_u = []
        for s in range(self.nspins):
            for k in range(kd.nbzkpts):
                # Index of symmetry related point in the IBZ
                ik = self.kd.bz2ibz_k[k]
                r, u = self.kd.get_rank_and_index(s, ik)
                assert r == 0
                kpt = self.kpt_u[u]
            
                phase_cd = np.exp(2j * np.pi * self.gd.sdisp_cd *
                                  kd.bzk_kc[k, :, np.newaxis])

                # New k-point:
                kpt2 = KPoint(weight, s, k, k, phase_cd)
                kpt2.f_n = kpt.f_n / kpt.weight / kd.nbzkpts * 2 / self.nspins
                kpt2.eps_n = kpt.eps_n.copy()
                
                # Transform wave functions using symmetry operation:
                Psit_nG = self.gd.collect(kpt.psit_nG)
                if Psit_nG is not None:
                    Psit_nG = Psit_nG.copy()
                    for Psit_G in Psit_nG:
                        Psit_G[:] = self.kd.transform_wave_function(Psit_G, k)
                kpt2.psit_nG = self.gd.empty(self.bd.nbands, dtype=self.dtype)
                self.gd.distribute(Psit_nG, kpt2.psit_nG)

                # Calculate PAW projections:
                kpt2.P_ani = self.pt.dict(len(kpt.psit_nG))
                self.pt.integrate(kpt2.psit_nG, kpt2.P_ani, k)
                
                kpt_u.append(kpt2)

        self.kd = kd
        self.kpt_u = kpt_u

    def write(self, writer, write_wave_functions=False):
        writer['Mode'] = 'fd'

        if not write_wave_functions:
            return

        writer.add('PseudoWaveFunctions',
                   ('nspins', 'nibzkpts', 'nbands',
                    'ngptsx', 'ngptsy', 'ngptsz'),
                   dtype=self.dtype)

        if hasattr(writer, 'hdf5'):
            parallel = (self.world.size > 1)
            for kpt in self.kpt_u:
                indices = [kpt.s, kpt.k]
                indices.append(self.bd.get_slice())
                indices += self.gd.get_slice()
                writer.fill(kpt.psit_nG, parallel=parallel, *indices)
        else:
            for s in range(self.nspins):
                for k in range(self.nibzkpts):
                    for n in range(self.bd.nbands):
                        psit_G = self.get_wave_function_array(n, k, s)
                        writer.fill(psit_G, s, k, n)

    def read(self, reader, hdf5):
        if ((not hdf5 and self.bd.comm.size == 1) or
            (hdf5 and self.world.size == 1)):
            # We may not be able to keep all the wave
            # functions in memory - so psit_nG will be a special type of
            # array that is really just a reference to a file:
            for kpt in self.kpt_u:
                kpt.psit_nG = reader.get_reference('PseudoWaveFunctions',
                                                   (kpt.s, kpt.k))
        else:
            for kpt in self.kpt_u:
                kpt.psit_nG = self.empty(self.bd.mynbands)
                if hdf5:
                    indices = [kpt.s, kpt.k]
                    indices.append(self.bd.get_slice())
                    indices += self.gd.get_slice()
                    reader.get('PseudoWaveFunctions', out=kpt.psit_nG,
                               parallel=(self.world.size > 1), *indices)
                else:
                    # Read band by band to save memory
                    for myn, psit_G in enumerate(kpt.psit_nG):
                        n = self.bd.global_index(myn)
                        if self.gd.comm.rank == 0:
                            big_psit_G = np.array(
                                reader.get('PseudoWaveFunctions',
                                           kpt.s, kpt.k, n),
                                self.dtype)
                        else:
                            big_psit_G = None
                        self.gd.distribute(big_psit_G, psit_G)
        
    def initialize_from_lcao_coefficients(self, basis_functions, mynbands):
        for kpt in self.kpt_u:
            kpt.psit_nG = self.gd.zeros(self.bd.mynbands, self.dtype)
            basis_functions.lcao_to_grid(kpt.C_nM,
                                         kpt.psit_nG[:mynbands], kpt.q)
            kpt.C_nM = None

    def random_wave_functions(self, nao):
        """Generate random wave functions."""

        gpts = self.gd.N_c[0] * self.gd.N_c[1] * self.gd.N_c[2]
        
        if self.bd.nbands < gpts / 64:
            gd1 = self.gd.coarsen()
            gd2 = gd1.coarsen()

            psit_G1 = gd1.empty(dtype=self.dtype)
            psit_G2 = gd2.empty(dtype=self.dtype)

            interpolate2 = Transformer(gd2, gd1, 1, self.dtype).apply
            interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply

            shape = tuple(gd2.n_c)
            scale = np.sqrt(12 / abs(np.linalg.det(gd2.cell_cv)))

            old_state = np.random.get_state()

            np.random.seed(4 + self.world.rank)

            for kpt in self.kpt_u:
                for psit_G in kpt.psit_nG[nao:]:
                    if self.dtype == float:
                        psit_G2[:] = (np.random.random(shape) - 0.5) * scale
                    else:
                        psit_G2.real = (np.random.random(shape) - 0.5) * scale
                        psit_G2.imag = (np.random.random(shape) - 0.5) * scale

                    interpolate2(psit_G2, psit_G1, kpt.phase_cd)
                    interpolate1(psit_G1, psit_G, kpt.phase_cd)
            np.random.set_state(old_state)
        
        elif gpts / 64 <= self.bd.nbands < gpts / 8:
            gd1 = self.gd.coarsen()

            psit_G1 = gd1.empty(dtype=self.dtype)

            interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply

            shape = tuple(gd1.n_c)
            scale = np.sqrt(12 / abs(np.linalg.det(gd1.cell_cv)))

            old_state = np.random.get_state()

            np.random.seed(4 + self.world.rank)

            for kpt in self.kpt_u:
                for psit_G in kpt.psit_nG[nao:]:
                    if self.dtype == float:
                        psit_G1[:] = (np.random.random(shape) - 0.5) * scale
                    else:
                        psit_G1.real = (np.random.random(shape) - 0.5) * scale
                        psit_G1.imag = (np.random.random(shape) - 0.5) * scale

                    interpolate1(psit_G1, psit_G, kpt.phase_cd)
            np.random.set_state(old_state)
               
        else:
            shape = tuple(self.gd.n_c)
            scale = np.sqrt(12 / abs(np.linalg.det(self.gd.cell_cv)))

            old_state = np.random.get_state()

            np.random.seed(4 + self.world.rank)

            for kpt in self.kpt_u:
                for psit_G in kpt.psit_nG[nao:]:
                    if self.dtype == float:
                        psit_G[:] = (np.random.random(shape) - 0.5) * scale
                    else:
                        psit_G.real = (np.random.random(shape) - 0.5) * scale
                        psit_G.imag = (np.random.random(shape) - 0.5) * scale

            np.random.set_state(old_state)

    def estimate_memory(self, mem):
        FDPWWaveFunctions.estimate_memory(self, mem)
Beispiel #34
0
    def set_grid_descriptor(self, gd):
        self.gd = gd
        axes = np.arange(3)
        pbc_c = np.array(gd.pbc_c, dtype=bool)
        periodic_axes = axes[pbc_c]
        non_periodic_axes = axes[np.logical_not(pbc_c)]

        # Find out which axes are orthogonal (0, 1 or 3)
        # Note that one expects that the axes are always rotated in
        # conventional form, thus for all axes to be
        # classified as orthogonal, the cell_cv needs to be diagonal.
        # This may always be achieved by rotating
        # the unit-cell along with the atoms. The classification is
        # inherited from grid_descriptor.orthogonal.
        dotprods = np.dot(gd.cell_cv, gd.cell_cv.T)
        # For each direction, check whether there is only one nonzero
        # element in that row (necessarily being the diagonal element,
        # since this is a cell vector length and must be > 0).
        orthogonal_c = (np.abs(dotprods) > 1e-10).sum(axis=0) == 1
        assert sum(orthogonal_c) in [0, 1, 3]

        non_orthogonal_axes = axes[np.logical_not(orthogonal_c)]

        if not all(pbc_c | orthogonal_c):
            raise BadAxesError('Each axis must be periodic or orthogonal '
                               'to other axes.  But we have pbc={} '
                               'and orthogonal={}'.format(
                                   pbc_c.astype(int),
                                   orthogonal_c.astype(int)))

        # We sort them, and pick the longest non-periodic axes as the
        # cholesky axis.
        sorted_non_periodic_axes = sorted(non_periodic_axes,
                                          key=lambda c: gd.N_c[c])
        if self.use_cholesky:
            if len(sorted_non_periodic_axes) > 0:
                cholesky_axes = [sorted_non_periodic_axes[-1]]
                if cholesky_axes[0] in non_orthogonal_axes:
                    msg = ('Cholesky axis cannot be non-orthogonal. '
                           'Do you really want a non-orthogonal non-periodic '
                           'axis? If so, run with use_cholesky=False.')
                    raise NotImplementedError(msg)
                fst_axes = sorted_non_periodic_axes[0:-1]
            else:
                cholesky_axes = []
                fst_axes = []
        else:
            cholesky_axes = []
            fst_axes = sorted_non_periodic_axes
        fft_axes = list(periodic_axes)

        (self.cholesky_axes, self.fst_axes,
         self.fft_axes) = cholesky_axes, fst_axes, fft_axes

        fftfst_axes = self.fft_axes + self.fst_axes
        axes = self.fft_axes + self.fst_axes + self.cholesky_axes
        self.axes = axes
        gd_x = [self.gd]

        # Create xy flat decomposition (where x=axes[0] and y=axes[1])
        domain = gd.N_c.copy()
        domain[axes[0]] = 1
        domain[axes[1]] = 1
        parsize_c = decompose_domain(domain, gd.comm.size)
        gd_x.append(gd.new_descriptor(parsize_c=parsize_c))

        # Create z flat decomposition
        domain = gd.N_c.copy()
        domain[axes[2]] = 1
        parsize_c = decompose_domain(domain, gd.comm.size)
        gd_x.append(gd.new_descriptor(parsize_c=parsize_c))
        self.gd_x = gd_x

        # Calculate eigenvalues in fst/fft decomposition for
        # non-cholesky axes in parallel
        r_cx = np.indices(gd_x[-1].n_c)
        r_cx += gd_x[-1].beg_c[:, np.newaxis, np.newaxis, np.newaxis]
        r_cx = r_cx.astype(complex)
        for c, axis in enumerate(fftfst_axes):
            r_cx[axis] *= 2j * np.pi / gd_x[-1].N_c[axis]
            if axis in fst_axes:
                r_cx[axis] /= 2
        for c, axis in enumerate(cholesky_axes):
            r_cx[axis] = 0.0
        np.exp(r_cx, out=r_cx)
        fft_lambdas = np.zeros_like(r_cx[0], dtype=complex)
        laplace = Laplace(gd_x[-1], -0.25 / pi, self.nn)
        self.stencil_description = laplace.description

        for coeff, offset_c in zip(laplace.coef_p, laplace.offset_pc):
            offset_c = np.array(offset_c)
            if not any(offset_c):
                # The centerpoint is handled with (temp-1.0)
                continue
            non_zero_axes, = np.where(offset_c)
            if set(non_zero_axes).issubset(fftfst_axes):
                temp = np.ones_like(fft_lambdas)
                for c, axis in enumerate(fftfst_axes):
                    temp *= r_cx[axis]**offset_c[axis]
                fft_lambdas += coeff * (temp - 1.0)

        assert np.linalg.norm(fft_lambdas.imag) < 1e-10
        fft_lambdas = fft_lambdas.real.copy()  # arr.real is not contiguous

        # If there is no Cholesky decomposition, the system is already
        # fully diagonal and we can directly invert the linear problem
        # by dividing with the eigenvalues.
        assert len(cholesky_axes) == 0
        # if len(cholesky_axes) == 0:
        with np.errstate(divide='ignore'):
            self.inv_fft_lambdas = np.where(
                np.abs(fft_lambdas) > 1e-10, 1.0 / fft_lambdas, 0)
Beispiel #35
0
""" Test the finite difference stencil """

from gpaw.grid_descriptor import GridDescriptor
from gpaw.fd_operators import Laplace
from gpaw.test import equal
import numpy as np

gpts = 64
nbands = 120
gd = GridDescriptor([gpts, gpts, gpts])

a = gd.empty(nbands)
b = gd.empty(nbands)

np.random.seed(10)
a[:] = np.random.random(a.shape)

op = Laplace(gd, 1.0, 3).apply
op(a, b)

equal(np.sum(b), -7.43198208966e-05, 1e-9)
Beispiel #36
0
import numpy as np
from gpaw.grid_descriptor import GridDescriptor
from gpaw.fd_operators import Laplace
from gpaw.mpi import rank, size, world

G = 40
N = 2 * 3 * 2 * 5 * 7 * 8 * 3 * 11
B = 2
h = 0.2
a = h * R
M = N // B
assert M * B == N
D = size // B
assert D * B == size
r = rank // B * B
domain_comm = mpi.world.new_communicator(np.arange(r, r + D))
band_comm = mpi.world.new_communicator(np.arange(rank, size, D))
gd = GridDescriptor((G, G, G), (a, a, a), comm=domain_comm)

np.random.seed(rank)
psit_mG = np.random.uniform(size=(M, ) + tuple(gd.n_c))
send_mG = gd.empty(M)
recv_mG = gd.empty(M)

laplace = [Laplace(g, n=1).apply for g in gd]

for i in range(B // 2):
    rrequest = band_comm.reveive(recv_mG, (rank + D) % size, 42, 0)
    srequest = band_comm.send(send_mG, (rank - D) % size, 17, 0)
Beispiel #37
0
        # Strange one!
        continue

    print('------------------')
    print(name, D)
    print(cell[0])
    print(cell[1])
    print(cell[2])
    for n in range(1, 6):
        N = 2 * n + 2
        gd = GridDescriptor((N, N, N), cell)
        b_g = gd.zeros()
        r_gv = gd.get_grid_point_coordinates().transpose((1, 2, 3, 0))
        c_v = gd.cell_cv.sum(0) / 2
        r_gv -= c_v
        lap = Laplace(gd, n=n)
        grad_v = [Gradient(gd, v, n=n) for v in range(3)]
        assert lap.npoints == D * 2 * n + 1
        for m in range(0, 2 * n + 1):
            for ix in range(m + 1):
                for iy in range(m - ix + 1):
                    iz = m - ix - iy
                    a_g = (r_gv**(ix, iy, iz)).prod(3)
                    if ix + iy + iz == 2 and max(ix, iy, iz) == 2:
                        r = 2.0
                    else:
                        r = 0.0
                    lap.apply(a_g, b_g)
                    e = b_g[n + 1, n + 1, n + 1] - r
                    assert abs(e) < 2e-12, e
                    for v in range(3):
Beispiel #38
0
def test(cellno, cellname, cell_cv, idiv, pbc, nn):
    N_c = h2gpts(0.12, cell_cv, idiv=idiv)
    if idiv == 1:
        N_c += 1 - N_c % 2  # We want especially to test uneven grids
    gd = GridDescriptor(N_c, cell_cv, pbc_c=pbc)
    rho_g = gd.zeros()
    phi_g = gd.zeros()
    rho_g[:] = -0.3 + rng.rand(*rho_g.shape)

    # Neutralize charge:
    charge = gd.integrate(rho_g)
    magic = gd.get_size_of_global_array().prod()
    rho_g -= charge / gd.dv / magic
    charge = gd.integrate(rho_g)
    assert abs(charge) < 1e-12

    # Check use_cholesky=True/False ?
    from gpaw.poisson import FDPoissonSolver
    ps = FastPoissonSolver(nn=nn)
    #print('setgrid')

    # Will raise BadAxesError for some pbc/cell combinations
    ps.set_grid_descriptor(gd)

    ps.solve(phi_g, rho_g)

    laplace = Laplace(gd, scale=-1.0 / (4.0 * np.pi), n=nn)

    def get_residual_err(phi_g):
        rhotest_g = gd.zeros()
        laplace.apply(phi_g, rhotest_g)
        residual = np.abs(rhotest_g - rho_g)
        # Residual is not accurate at end of non-periodic directions
        # except for nn=1 (since effectively we use the right stencil
        # only for nn=1 at the boundary).
        #
        # To do this check correctly, the Laplacian should have lower
        # nn at the boundaries.  Therefore we do not test the residual
        # at these ends, only in between, by zeroing the bad ones:
        if nn > 1:
            exclude_points = nn - 1
            for c in range(3):
                if nn > 1 and not pbc[c]:
                    # get view ehere axis c refers becomes zeroth dimension:
                    X = residual.transpose(c, (c + 1) % 3, (c + 2) % 3)

                    if gd.beg_c[c] == 1:
                        X[:exclude_points] = 0.0
                    if gd.end_c[c] == gd.N_c[c]:
                        X[-exclude_points:] = 0.0
        return residual.max()

    maxerr = get_residual_err(phi_g)
    pbcstring = '{}{}{}'.format(*pbc)

    if 0:
        ps2 = FDPoissonSolver(relax='J', nn=nn, eps=1e-18)
        ps2.set_grid_descriptor(gd)
        phi2_g = gd.zeros()
        ps2.solve(phi2_g, rho_g)

        phimaxerr = np.abs(phi2_g - phi_g).max()
        maxerr2 = get_residual_err(phi2_g)
        msg = ('{:2d} {:8s} pbc={} err={:8.5e} err[J]={:8.5e} '
               'err[phi]={:8.5e} nn={:1d}'
               .format(cellno, cellname, pbcstring, maxerr, maxerr2,
                       phimaxerr, nn))

    state = 'ok' if maxerr < tolerance else 'FAIL'

    msg = ('{:2d} {:8s} grid={} pbc={} err[fast]={:8.5e} nn={:1d} {}'
           .format(cellno, cellname, N_c, pbcstring, maxerr, nn, state))
    if world.rank == 0:
        print(msg)

    return maxerr
Beispiel #39
0
# Set up band and grid descriptors:
bd = BandDescriptor(N, band_comm, False)
gd = GridDescriptor((G, G, G), (a, a, a), True, domain_comm, parsize_c=D)
ksl = BandLayouts(gd, bd, block_comm, float)

# Random wave functions:
psit_mG = gd.empty(M)
for m in range(M):
    np.random.seed(world.rank * M + m)
    psit_mG[m] = np.random.uniform(-0.5, 0.5, tuple(gd.n_c))
if world.rank == 0:
    print('Size of wave function array:', psit_mG.shape)
P_ani = {0: psit_mG[:, :2, 0, 0].copy(), 1: psit_mG[:, -1, -1, -3:].copy()}

kin = Laplace(gd, -0.5, 2).apply
vt_G = gd.empty()
vt_G.fill(0.567)


def run(psit_mG):
    overlap = MatrixOperator(ksl, J)

    def H(psit_xG):
        Htpsit_xG = np.empty_like(psit_xG)
        kin(psit_xG, Htpsit_xG)
        for psit_G, y_G in zip(psit_xG, Htpsit_xG):
            y_G += vt_G * psit_G
        return Htpsit_xG

    dH_aii = {0: np.ones((2, 2)) * 0.123, 1: np.ones((3, 3)) * 0.321}
Beispiel #40
0
class SternheimerOperator:
    """Class implementing the linear operator in the Sternheimer equation.
    
    The main purpose of this class is to implement the multiplication of the
    linear operator (H - eps_nk) with a vector in the ``apply`` member
    function. An additional ``matvec`` member function has been defined so that
    instances of this class can be passed as a linear operator to scipy's
    iterative Krylov solvers in ``scipy.sparse.linalg``.

    """
    def __init__(self, hamiltonian, wfs, gd, dtype=float):
        """Save useful objects for the Sternheimer operator.

        Parameters
        ----------
        hamiltonian: Hamiltonian
            Hamiltonian for a ground-state calculation.
        wfs: WaveFunctions
            Ground-state wave-functions.
        gd: GridDescriptor
            Grid on which the operator is defined.
        dtype: dtype
            dtype of the wave-function being operated on.

        """

        self.hamiltonian = hamiltonian
        self.kin = Laplace(gd, scale=-0.5, n=3, dtype=dtype)
        self.kpt_u = wfs.kpt_u
        self.pt = wfs.pt
        self.gd = gd

        # Variables for k-point and band index
        self.k = None
        self.n = None
        self.kplusq = None

        # For scipy's linear solver
        N = np.prod(gd.n_c)
        self.shape = (N, N)
        self.dtype = dtype

    def set_k(self, k):
        """Set k-vector for the Bloch-state in consideration."""

        self.k = k

    def set_band(self, n):
        """Set band index for the Bloch-state in consideration.

        Note that n different from None has implications for the interpretation
        of the input vector in the ``apply`` member function.

        """

        self.n = n

    def set_kplusq(self, kplusq):
        """Set q-vector of the perturbing potential.

        Parameters
        ----------
        kplusq: int
           Index of the k+q vector.

        """

        self.kplusq = kplusq

    def apply(self, x_nG, y_nG):
        """Apply the linear operator in the Sternheimer equation to a vector.

        For the eigenvalue term the k-point is the one of the state.
        For the other terms the k-point to be used is the one given by the k+q
        phase of the first-order of the state. Only for q=0 do the two coincide.
        
        Parameters
        ----------
        x_nG: ndarray
            Vector(s) to which the Sternheimer operator is applied.
        y_nG: ndarray
            Resulting vector(s).
            
        """

        assert x_nG.ndim in (3, 4)
        assert x_nG.shape == y_nG.shape
        assert tuple(self.gd.n_c) == x_nG.shape[-3:]
        assert self.k is not None

        # k
        kpt = self.kpt_u[self.k]
        # k+q
        kplusqpt = self.kpt_u[self.kplusq]

        # Kintetic energy
        # k+q
        self.kin.apply(x_nG, y_nG, phase_cd=kplusqpt.phase_cd)

        # Local part of effective potential - no phase !!
        self.hamiltonian.apply_local_potential(x_nG, y_nG, kpt.s)

        # Non-local part from projectors (coefficients can not be reused)
        shape = x_nG.shape[:-3]
        P_ani = self.pt.dict(shape=shape)

        # k+q
        self.pt.integrate(x_nG, P_ani, q=kplusqpt.k)

        for a, P_ni in P_ani.items():
            dH_ii = unpack(self.hamiltonian.dH_asp[a][kpt.s])
            P_ani[a] = np.dot(P_ni, dH_ii)
        # k+q
        self.pt.add(y_nG, P_ani, q=kplusqpt.k)

        # XXX Eigenvalue term
        if self.n is not None:
            # k
            y_nG -= kpt.eps_n[self.n] * x_nG
        else:
            for n, x_G in enumerate(x_nG):
                # k
                y_nG[n] -= kpt.eps_n[n] * x_G

        # Project out undesired (numerical) components
        # k+q
        self.project(y_nG)

    def project(self, x_nG):
        """Project the vector onto the unoccupied states at k+q.

        The projection operator is defined as follows::

                      --                    --             
             P      = >  |Psi ><Psi | = 1 - >  |Psi ><Psi |
              c,k+q   --     c     c        --     v     v 
                       c    k+q   k+q        v    k+q   k+q
        
        """

        # It might be a good idea to move this functionality to its own class
        assert x_nG.ndim == 4
        assert self.kplusq is not None

        # k+q
        kplusqpt = self.kpt_u[self.kplusq]
        # Occupied wave function
        psit_nG = kplusqpt.psit_nG

        # Project out occupied sub-space using blas routine gemm
        m = len(x_nG)
        n = len(psit_nG)
        proj_mn = np.zeros((m, n), dtype=self.dtype)
        gemm(self.gd.dv, psit_nG, x_nG, 0.0, proj_mn, 'c')
        gemm(-1.0, psit_nG, proj_mn, 1.0, x_nG)

        # Project out one orbital at a time
        ## for n, psit_G in enumerate(psit_nG):
        ##
        ##     proj = self.gd.integrate(psit_G.conjugate() * x_nG)
        ##     x_nG -= proj * psit_G

    def matvec(self, x):
        """Matrix-vector multiplication for scipy's Krylov solvers.

        This is a wrapper around the ``apply`` member function above. It allows
        to multiply the sternheimer operator onto the 1-dimensional scipy
        representation of a gpaw grid vector(s).
        
        Parameters
        ----------
        a: ndarray
            1-dimensional array holding the representation of a gpaw grid
            vector (possibly a set of vectors).

        """

        # Check that a is 1-dimensional
        assert len(x.shape) == 1

        # Find the number of states in x
        grid_shape = tuple(self.gd.n_c)
        assert ((x.size % np.prod(grid_shape)) == 0), ("Incompatible array " +
                                                       "shapes")
        # Number of states in the vector
        N = x.size / np.prod(grid_shape)

        # Output array
        y_nG = self.gd.zeros(n=N, dtype=self.dtype)
        shape = y_nG.shape

        assert x.size == np.prod(y_nG.shape)

        x_nG = x.reshape(shape)

        self.apply(x_nG, y_nG)

        y = y_nG.ravel()

        return y