Пример #1
0
    def run(self, nsteps, inverse_overlap='exact'):

        if inverse_overlap == 'exact':
            self.solver = self.solve
        elif inverse_overlap == 'approximate':
            self.solver = self.solve2
        elif inverse_overlap == 'noinverse':
            self.solver = self.solve3
        else:
            raise RuntimeError("Error, inverse_solver must be either 'exact' "
                               "'approximate' or 'noinverse'")

        self.overlap = Overlap()

        ni = self.a_uci.shape[2]
        a_uci = np.empty((self.nmykpts, self.dim, ni + nsteps), self.wfs.dtype)
        b_uci = np.empty((self.nmykpts, self.dim, ni + nsteps), self.wfs.dtype)
        a_uci[:, :, :ni] = self.a_uci
        b_uci[:, :, :ni] = self.b_uci
        self.a_uci = a_uci
        self.b_uci = b_uci

        for u in range(self.nmykpts):
            for i in range(nsteps):
                self.step(u, ni + i)
Пример #2
0
    def __init__(self, ksl, timer):
        """Creates the TimeDependentOverlap-object.
        
        Parameters
        ----------
        XXX TODO

        """
        Overlap.__init__(self, ksl, timer)
Пример #3
0
    def __init__(self, ksl, timer):
        """Creates the TimeDependentOverlap-object.
        
        Parameters
        ----------
        XXX TODO

        """
        Overlap.__init__(self, ksl, timer)
Пример #4
0
    def __init__(self, diagksl, orthoksl, initksl, *args, **kwargs):
        WaveFunctions.__init__(self, *args, **kwargs)

        self.diagksl = diagksl
        self.orthoksl = orthoksl
        self.initksl = initksl

        self.set_orthonormalized(False)

        self.overlap = Overlap(orthoksl, self.timer)
Пример #5
0
    def __init__(self, diagksl, orthoksl, initksl, *args, **kwargs):
        WaveFunctions.__init__(self, *args, **kwargs)

        self.diagksl = diagksl
        self.orthoksl = orthoksl
        self.initksl = initksl

        self.set_orthonormalized(False)

        self.overlap = Overlap(orthoksl, self.timer)
Пример #6
0
    def __init__(self, wfs, atoms):
        """TODO

        Attributes:

        ============  ======================================================
        ``B_aa``      < p_i^a | p_i'^a' >
        ``xO_aa``     TODO
        ``dC_aa``     TODO
        ``xC_aa``     TODO
        ============  ======================================================
        """

        Overlap.__init__(self, wfs.orthoksl, wfs.timer)
        GridPairOverlap.__init__(self, wfs.gd, wfs.setups)
        self.natoms = len(atoms)
        if debug:
            assert len(self.setups) == self.natoms
        self.update(wfs, atoms)
    def __init__(self, wfs, atoms):
        """TODO

        Attributes:

        ============  ======================================================
        ``B_aa``      < p_i^a | p_i'^a' >
        ``xO_aa``     TODO
        ``dC_aa``     TODO
        ``xC_aa``     TODO
        ============  ======================================================
        """

        Overlap.__init__(self, wfs.orthoksl, wfs.timer)
        GridPairOverlap.__init__(self, wfs.gd, wfs.setups)
        self.natoms = len(atoms)
        if debug:
            assert len(self.setups) == self.natoms
        self.update(wfs, atoms)
Пример #8
0
class FDPWWaveFunctions(WaveFunctions):
    """Base class for finite-difference and planewave classes."""
    def __init__(self, diagksl, orthoksl, initksl, *args, **kwargs):
        WaveFunctions.__init__(self, *args, **kwargs)

        self.diagksl = diagksl
        self.orthoksl = orthoksl
        self.initksl = initksl

        self.set_orthonormalized(False)

        self.overlap = Overlap(orthoksl, self.timer)

    def set_setups(self, setups):
        WaveFunctions.set_setups(self, setups)
        if not self.gamma:
            self.pt.set_k_points(self.kd.ibzk_qc)

    def set_orthonormalized(self, flag):
        self.orthonormalized = flag

    def set_positions(self, spos_ac):
        WaveFunctions.set_positions(self, spos_ac)
        self.set_orthonormalized(False)
        self.pt.set_positions(spos_ac)
        self.allocate_arrays_for_projections(self.pt.my_atom_indices)
        self.positions_set = True

    def initialize(self, density, hamiltonian, spos_ac):
        if self.kpt_u[0].psit_nG is None:
            basis_functions = BasisFunctions(self.gd,
                                             [setup.phit_j
                                              for setup in self.setups],
                                             cut=True)
            if not self.gamma:
                basis_functions.set_k_points(self.kd.ibzk_qc)
            basis_functions.set_positions(spos_ac)
        elif isinstance(self.kpt_u[0].psit_nG, TarFileReference):
            self.initialize_wave_functions_from_restart_file()

        if self.kpt_u[0].psit_nG is not None:
            density.initialize_from_wavefunctions(self)
        elif density.nt_sG is None:
            density.initialize_from_atomic_densities(basis_functions)
            # Initialize GLLB-potential from basis function orbitals
            if hamiltonian.xc.type == 'GLLB':
                hamiltonian.xc.initialize_from_atomic_orbitals(
                    basis_functions)
        else: # XXX???
            # We didn't even touch density, but some combinations in paw.set()
            # will make it necessary to do this for some reason.
            density.calculate_normalized_charges_and_mix()
        hamiltonian.update(density)
                
        if self.kpt_u[0].psit_nG is None:
            self.initialize_wave_functions_from_basis_functions(
                basis_functions, density, hamiltonian, spos_ac)

    def initialize_wave_functions_from_basis_functions(self,
                                                       basis_functions,
                                                       density, hamiltonian,
                                                       spos_ac):
        if 0:
            self.timer.start('Random wavefunction initialization')
            for kpt in self.kpt_u:
                kpt.psit_nG = self.gd.zeros(self.mynbands, self.dtype)
                if extra_parameters.get('sic'):
                    kpt.W_nn = np.zeros((self.nbands, self.nbands),
                                        dtype=self.dtype)
            self.random_wave_functions(0)
            self.timer.stop('Random wavefunction initialization')
            return

        self.timer.start('LCAO initialization')
        lcaoksl, lcaobd = self.initksl, self.initksl.bd
        lcaowfs = LCAOWaveFunctions(lcaoksl, self.gd, self.nvalence,
                                    self.setups, lcaobd, self.dtype,
                                    self.world, self.kd)
        lcaowfs.basis_functions = basis_functions
        lcaowfs.timer = self.timer
        self.timer.start('Set positions (LCAO WFS)')
        lcaowfs.set_positions(spos_ac)
        self.timer.stop('Set positions (LCAO WFS)')

        eigensolver = get_eigensolver('lcao', 'lcao')
        eigensolver.initialize(self.gd, self.dtype, self.setups.nao, lcaoksl)

        # XXX when density matrix is properly distributed, be sure to
        # update the density here also
        eigensolver.iterate(hamiltonian, lcaowfs)

        # Transfer coefficients ...
        for kpt, lcaokpt in zip(self.kpt_u, lcaowfs.kpt_u):
            kpt.C_nM = lcaokpt.C_nM

        # and get rid of potentially big arrays early:
        del eigensolver, lcaowfs

        self.timer.start('LCAO to grid')
        for kpt in self.kpt_u:
            kpt.psit_nG = self.gd.zeros(self.mynbands, self.dtype)
            if extra_parameters.get('sic'):
                kpt.W_nn = np.zeros((self.nbands, self.nbands),
                                    dtype=self.dtype)
            basis_functions.lcao_to_grid(kpt.C_nM, 
                                         kpt.psit_nG[:lcaobd.mynbands], kpt.q)
            kpt.C_nM = None
        self.timer.stop('LCAO to grid')

        if self.mynbands > lcaobd.mynbands:
            # Add extra states.  If the number of atomic orbitals is
            # less than the desired number of bands, then extra random
            # wave functions are added.
            self.random_wave_functions(lcaobd.mynbands)
        self.timer.stop('LCAO initialization')

    def initialize_wave_functions_from_restart_file(self):
        if not isinstance(self.kpt_u[0].psit_nG, TarFileReference):
            return

        # Calculation started from a restart file.  Copy data
        # from the file to memory:
        for kpt in self.kpt_u:
            file_nG = kpt.psit_nG
            kpt.psit_nG = self.gd.empty(self.mynbands, self.dtype)
            if extra_parameters.get('sic'):
                kpt.W_nn = np.zeros((self.nbands, self.nbands),
                                    dtype=self.dtype)
            # Read band by band to save memory
            for n, psit_G in enumerate(kpt.psit_nG):
                if self.gd.comm.rank == 0:
                    big_psit_G = np.array(file_nG[n][:], self.dtype)
                else:
                    big_psit_G = None
                self.gd.distribute(big_psit_G, psit_G)
        
    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.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.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 orthonormalize(self):
        for kpt in self.kpt_u:
            self.overlap.orthonormalize(self, kpt)
        self.set_orthonormalized(True)

    def _get_wave_function_array(self, u, n):
        psit_nG = self.kpt_u[u].psit_nG
        if psit_nG is None:
            raise RuntimeError('This calculator has no wave functions!')
        return psit_nG[n][:] # dereference possible tar-file content

    def write_wave_functions(self, writer):
        try:
            from gpaw.io.hdf5 import Writer as HDF5Writer
        except ImportError:
            hdf5 = False
        else:
            hdf5 = isinstance(writer, HDF5Writer)
            
        if self.world.rank == 0 or hdf5:
            writer.add('PseudoWaveFunctions',
                       ('nspins', 'nibzkpts', 'nbands',
                        'ngptsx', 'ngptsy', 'ngptsz'),
                       dtype=self.dtype)

        if hdf5:
            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=True, *indices)
        else:
            for s in range(self.nspins):
                for k in range(self.nibzkpts):
                    for n in range(self.nbands):
                        psit_G = self.get_wave_function_array(n, k, s)
                        if self.world.rank == 0:
                            writer.fill(psit_G, s, k, n)

    def estimate_memory(self, mem):
        gridbytes = self.gd.bytecount(self.dtype)
        mem.subnode('Arrays psit_nG', 
                    len(self.kpt_u) * self.mynbands * gridbytes)
        self.eigensolver.estimate_memory(mem.subnode('Eigensolver'), self.gd,
                                         self.dtype, self.mynbands,
                                         self.nbands)
        self.pt.estimate_memory(mem.subnode('Projectors'))
        self.matrixoperator.estimate_memory(mem.subnode('Overlap op'),
                                            self.dtype)
Пример #9
0
    def apply_inverse(self,
                      a_nG,
                      b_nG,
                      wfs,
                      kpt,
                      calculate_P_ani=True,
                      use_cg=True):
        """Apply the approximative time-dependent inverse overlap operator
        to the wavefunction psit of the k-point kpt.
    
        Parameters
        ----------
        a_nG: List of coarse grids
            the wavefuntions (on coarse grid)
            (kpt_u[index_of_k-point].psit_nG[indices_of_wavefunc])
        b_nG: List of coarse grids
            the resulting "operated wavefunctions" (S^(-1) psit)
        wfs: TimeDependentWaveFunctions
            time-independent grid-based wavefunctions
        kpt: Kpoint
            the current k-point (kpt_u[index_of_k-point])
        calculate_P_ani: bool
            When True, the integrals of projector times vectors
            P_ni = <p_i | psit> are calculated.
            When False, existing P_uni are used
        use_cg: bool
            When True, use conjugate gradient method to solve for inverse.
    
        """
        if not use_cg:
            self.timer.start('Apply approximate inverse overlap')
            Overlap.apply_inverse(self, a_nG, b_nG, wfs, kpt, calculate_P_ani)
            self.timer.stop('Apply approximate inverse overlap')
            return

        self.timer.start('Apply exact inverse overlap')
        from gpaw.utilities.blas import dotu, axpy

        #from gpaw.tddft.cscg import multi_zdotu, multi_scale, multi_zaxpy
        #initialization
        # Multivector dot product, a^T b, where ^T is transpose
        def multi_zdotu(s, x, y, nvec):
            for i in range(nvec):
                s[i] = dotu(x[i], y[i])
            wfs.gd.comm.sum(s)
            return s

        # Multivector ZAXPY: a x + y => y
        def multi_zaxpy(a, x, y, nvec):
            for i in range(nvec):
                axpy(a[i] * (1 + 0J), x[i], y[i])

        # Multiscale: a x => x
        def multi_scale(a, x, nvec):
            for i in range(nvec):
                x[i] *= a[i]

        nvec = len(a_nG)
        r = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        z = wfs.gd.zeros((nvec, ), dtype=wfs.dtype)
        p = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        q = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        alpha = np.zeros((nvec, ), dtype=wfs.dtype)
        beta = np.zeros((nvec, ), dtype=wfs.dtype)
        scale = np.zeros((nvec, ), dtype=wfs.dtype)
        normr2 = np.zeros((nvec, ), dtype=wfs.dtype)
        rho = np.zeros((nvec, ), dtype=wfs.dtype)
        rho_prev = np.zeros((nvec, ), dtype=wfs.dtype)
        rho_prev[:] = 1.0
        tol_cg = 1e-14
        multi_zdotu(scale, a_nG, a_nG, nvec)
        scale = np.abs(scale)

        x = b_nG  #XXX TODO rename this

        #x0 = S^-1_approx a_nG
        self.apply_inverse(a_nG, x, wfs, kpt, calculate_P_ani, use_cg=False)
        #r0 = a_nG - S x_0
        self.apply(-x, r, wfs, kpt, calculate_P_ani)
        r += a_nG
        #print 'r.max() =', abs(r).max()

        max_iter = 50

        for i in range(max_iter):

            #print 'iter =', i

            self.apply_inverse(r, z, wfs, kpt, calculate_P_ani, use_cg=False)

            multi_zdotu(rho, r, z, nvec)

            beta = rho / rho_prev
            multi_scale(beta, p, nvec)
            p += z

            self.apply(p, q, wfs, kpt, calculate_P_ani)

            multi_zdotu(alpha, p, q, nvec)
            alpha = rho / alpha

            multi_zaxpy(alpha, p, x, nvec)
            multi_zaxpy(-alpha, q, r, nvec)

            multi_zdotu(normr2, r, r, nvec)

            #rhoc = rho.copy()
            rho_prev[:] = rho.copy()
            #rho.copy()
            #rho_prev = rho.copy()

            #print '||r|| =', np.sqrt(np.abs(normr2/scale))
            if ((np.sqrt(np.abs(normr2) / scale)) < tol_cg).all():
                break

        self.timer.stop('Apply exact inverse overlap')
Пример #10
0
    def apply_inverse(self, a_nG, b_nG, wfs, kpt, calculate_P_ani=True, use_cg=True):
        """Apply the approximative time-dependent inverse overlap operator
        to the wavefunction psit of the k-point kpt.
    
        Parameters
        ----------
        a_nG: List of coarse grids
            the wavefuntions (on coarse grid) 
            (kpt_u[index_of_k-point].psit_nG[indices_of_wavefunc])
        b_nG: List of coarse grids
            the resulting "operated wavefunctions" (S^(-1) psit)
        wfs: TimeDependentWaveFunctions
            time-independent grid-based wavefunctions
        kpt: Kpoint
            the current k-point (kpt_u[index_of_k-point])
        calculate_P_ani: bool
            When True, the integrals of projector times vectors
            P_ni = <p_i | psit> are calculated.
            When False, existing P_uni are used
        use_cg: bool
            When True, use conjugate gradient method to solve for inverse.
    
        """
        if not use_cg:
            self.timer.start('Apply approximate inverse overlap')
            Overlap.apply_inverse(self, a_nG, b_nG, wfs, kpt, calculate_P_ani)
            self.timer.stop('Apply approximate inverse overlap')
            return            

        self.timer.start('Apply exact inverse overlap')
        from gpaw.utilities.blas import dotu, axpy, dotc
        #from gpaw.tddft.cscg import multi_zdotu, multi_scale, multi_zaxpy
        #initialization
          # Multivector dot product, a^T b, where ^T is transpose
        def multi_zdotu(s, x,y, nvec):
            for i in range(nvec):
                s[i] = dotu(x[i],y[i])
            wfs.gd.comm.sum(s)
            return s
        # Multivector ZAXPY: a x + y => y
        def multi_zaxpy(a,x,y, nvec):
            for i in range(nvec):
                axpy(a[i]*(1+0J), x[i], y[i])
        # Multiscale: a x => x
        def multi_scale(a,x, nvec):
            for i in range(nvec):
                x[i] *= a[i]
        nvec = len(a_nG)
        r = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        z  = wfs.gd.zeros((nvec,), dtype=wfs.dtype)
        sx = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        p = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        q = wfs.gd.zeros(nvec, dtype=wfs.dtype)
        alpha = np.zeros((nvec,), dtype=wfs.dtype)
        beta = np.zeros((nvec,), dtype=wfs.dtype)
        scale = np.zeros((nvec,), dtype=wfs.dtype)
        normr2 = np.zeros((nvec,), dtype=wfs.dtype)
        rho  = np.zeros((nvec,), dtype=wfs.dtype) 
        rho_prev  = np.zeros((nvec,), dtype=wfs.dtype)
        rho_prev[:] = 1.0
        tol_cg = 1e-14
        multi_zdotu(scale, a_nG, a_nG, nvec)
        scale = np.abs(scale)

        x = b_nG #XXX TODO rename this

        #x0 = S^-1_approx a_nG
        self.apply_inverse(a_nG, x, wfs, kpt, calculate_P_ani, use_cg=False)
        #r0 = a_nG - S x_0
        self.apply(-x, r, wfs, kpt, calculate_P_ani)
        r += a_nG
        #print 'r.max() =', abs(r).max()

        max_iter = 50

        for i in range(max_iter):

            #print 'iter =', i

            self.apply_inverse(r, z, wfs, kpt, calculate_P_ani, use_cg=False)

            multi_zdotu(rho, r, z, nvec)

            beta = rho / rho_prev
            multi_scale(beta, p, nvec)
            p += z

            self.apply(p,q,wfs,kpt, calculate_P_ani)

            multi_zdotu(alpha, p, q, nvec)
            alpha = rho/alpha

            multi_zaxpy(alpha, p, x, nvec)
            multi_zaxpy(-alpha, q, r, nvec)

            multi_zdotu(normr2, r,r, nvec)

            #rhoc = rho.copy()
            rho_prev[:] = rho.copy()
            #rho.copy()
            #rho_prev = rho.copy()

            #print '||r|| =', np.sqrt(np.abs(normr2/scale))
            if ( (np.sqrt(np.abs(normr2) / scale)) < tol_cg ).all():
                break

        self.timer.stop('Apply exact inverse overlap')
Пример #11
0
class RecursionMethod:
    """This class implements the Haydock recursion method. """
    def __init__(self,
                 paw=None,
                 filename=None,
                 tol=1e-10,
                 maxiter=100,
                 proj=None,
                 proj_xyz=True):

        if paw is not None:
            wfs = paw.wfs
            assert wfs.gd.orthogonal

            self.wfs = wfs
            self.hamiltonian = paw.hamiltonian
            self.nkpts = len(wfs.kd.ibzk_kc) * wfs.nspins
            self.nmykpts = len(wfs.kpt_u)

            self.k1 = wfs.kd.comm.rank * self.nmykpts
            self.k2 = self.k1 + self.nmykpts

            print('k1', self.k1, 'k2', self.k2)

            # put spin and weight index in the columns corresponding
            # to this processors k-points
            self.spin_k = np.zeros(self.nkpts, int)
            self.weight_k = np.zeros(self.nkpts)

            for n, i in enumerate(range(self.k1, self.k2)):
                self.spin_k[i] = wfs.kpt_u[n].s
                self.weight_k[i] = wfs.kpt_u[n].weight

            self.op_scc = None
            if wfs.kd.symmetry is not None:
                self.op_scc = wfs.kd.symmetry.op_scc
        else:
            self.k1 = 0
            self.k2 = None
            self.wfs = None
            wfs = None

        self.tol = tol
        self.maxiter = maxiter

        if filename is not None:
            self.read(filename)
            if wfs is not None:
                self.allocate_tmp_arrays()
        else:
            self.initialize_start_vector(proj=proj, proj_xyz=proj_xyz)

    def read(self, filename):
        data = pickle.load(open(filename, 'rb'))
        self.nkpts = data['nkpts']
        if 'swaps' in data:
            # This is an old file:
            self.op_scc = np.array(
                [np.identity(3, int)[list(swap)] for swap in data['swaps']])
        else:
            self.op_scc = data['symmetry operations']
        self.weight_k = data['weight_k']
        self.spin_k = data['spin_k']
        self.dim = data['dim']
        k1, k2 = self.k1, self.k2
        if k2 is None:
            k2 = self.nkpts
        a_kci, b_kci = data['ab']
        self.a_uci = a_kci[k1:k2].copy()
        self.b_uci = b_kci[k1:k2].copy()

        if self.wfs is not None and 'arrays' in data:
            print('reading arrays')
            w_kcG, wold_kcG, y_kcG = data['arrays']
            i = [slice(k1, k2), slice(0, self.dim)] + self.wfs.gd.get_slice()
            self.w_ucG = w_kcG[i].copy()
            self.wold_ucG = wold_kcG[i].copy()
            self.y_ucG = y_kcG[i].copy()

    def write(self, filename, mode=''):
        assert self.wfs is not None
        kpt_comm = self.wfs.kd.comm
        gd = self.wfs.gd

        if gd.comm.rank == 0:
            if kpt_comm.rank == 0:
                nmyu, dim, ni = self.a_uci.shape
                a_kci = np.empty((kpt_comm.size, nmyu, dim, ni),
                                 self.wfs.dtype)
                b_kci = np.empty((kpt_comm.size, nmyu, dim, ni),
                                 self.wfs.dtype)

                kpt_comm.gather(self.a_uci, 0, a_kci)
                kpt_comm.gather(self.b_uci, 0, b_kci)
                kpt_comm.sum(self.spin_k, 0)
                kpt_comm.sum(self.weight_k, 0)

                a_kci.shape = (self.nkpts, dim, ni)
                b_kci.shape = (self.nkpts, dim, ni)
                data = {
                    'ab': (a_kci, b_kci),
                    'nkpts': self.nkpts,
                    'symmetry operations': self.op_scc,
                    'weight_k': self.weight_k,
                    'spin_k': self.spin_k,
                    'dim': dim
                }
            else:
                kpt_comm.gather(self.a_uci, 0)
                kpt_comm.gather(self.b_uci, 0)
                kpt_comm.sum(self.spin_k, 0)
                kpt_comm.sum(self.weight_k, 0)

        if mode == 'all':
            w0_ucG = gd.collect(self.w_ucG)
            wold0_ucG = gd.collect(self.wold_ucG)
            y0_ucG = gd.collect(self.y_ucG)
            if gd.comm.rank == 0:
                if kpt_comm.rank == 0:
                    w_kcG = gd.empty((self.nkpts, dim),
                                     self.wfs.dtype,
                                     global_array=True)
                    wold_kcG = gd.empty((self.nkpts, dim),
                                        self.wfs.dtype,
                                        global_array=True)
                    y_kcG = gd.empty((self.nkpts, dim),
                                     self.wfs.dtype,
                                     global_array=True)
                    kpt_comm.gather(w0_ucG, 0, w_kcG)
                    kpt_comm.gather(wold0_ucG, 0, wold_kcG)
                    kpt_comm.gather(y0_ucG, 0, y_kcG)
                    data['arrays'] = (w_kcG, wold_kcG, y_kcG)
                else:
                    kpt_comm.gather(w0_ucG, 0)
                    kpt_comm.gather(wold0_ucG, 0)
                    kpt_comm.gather(y0_ucG, 0)

        if self.wfs.world.rank == 0:
            pickle.dump(data, open(filename, 'wb'))

    def allocate_tmp_arrays(self):

        self.tmp1_cG = self.wfs.gd.zeros(self.dim, self.wfs.dtype)
        self.tmp2_cG = self.wfs.gd.zeros(self.dim, self.wfs.dtype)
        self.z_cG = self.wfs.gd.zeros(self.dim, self.wfs.dtype)

    def initialize_start_vector(self, proj=None, proj_xyz=True):
        # proj is one list of vectors [[e1_x,e1_y,e1_z],[e2_x,e2_y,e2_z]]
        # ( or [ex,ey,ez] if only one projection )
        # that the spectrum will be projected on
        # default is to only calculate the averaged spectrum
        # if proj_xyz is True, keep projection in x,y,z, if False
        # only calculate the projections in proj

        # Create initial wave function:
        nmykpts = self.nmykpts

        for a, setup in enumerate(self.wfs.setups):
            if setup.phicorehole_g is not None:
                break
        A_ci = setup.A_ci

        #
        # proj keyword
        #

        # check normalization of incoming vectors
        if proj is not None:
            proj_2 = np.array(proj, float)
            if len(proj_2.shape) == 1:
                proj_2 = np.array([proj], float)

            for i, p in enumerate(proj_2):
                if sum(p**2)**0.5 != 1.0:
                    print('proj_2 %s not normalized' % i)
                    proj_2[i] /= sum(p**2)**0.5

            proj_tmp = []
            for p in proj_2:
                proj_tmp.append(np.dot(p, A_ci))
            proj_tmp = np.array(proj_tmp, float)

            # if proj_xyz is True, append projections to A_ci
            if proj_xyz:
                A_ci_tmp = np.zeros((3 + proj_2.shape[0], A_ci.shape[1]))
                A_ci_tmp[0:3, :] = A_ci
                A_ci_tmp[3:, :] = proj_tmp

            # otherwise, replace A_ci by projections
            else:
                A_ci_tmp = np.zeros((proj_2.shape[0], A_ci.shape[1]))
                A_ci_tmp = proj_tmp
            A_ci = A_ci_tmp

        self.dim = len(A_ci)

        self.allocate_tmp_arrays()

        self.w_ucG = self.wfs.gd.zeros((nmykpts, self.dim), self.wfs.dtype)
        self.wold_ucG = self.wfs.gd.zeros((nmykpts, self.dim), self.wfs.dtype)
        self.y_ucG = self.wfs.gd.zeros((nmykpts, self.dim), self.wfs.dtype)

        self.a_uci = np.zeros((nmykpts, self.dim, 0), self.wfs.dtype)
        self.b_uci = np.zeros((nmykpts, self.dim, 0), self.wfs.dtype)

        A_aci = self.wfs.pt.dict(3, zero=True)
        if a in A_aci:
            A_aci[a] = A_ci.astype(self.wfs.dtype)
        for u in range(nmykpts):
            self.wfs.pt.add(self.w_ucG[u], A_aci, u)

    def run(self, nsteps, inverse_overlap='exact'):

        if inverse_overlap == 'exact':
            self.solver = self.solve
        elif inverse_overlap == 'approximate':
            self.solver = self.solve2
        elif inverse_overlap == 'noinverse':
            self.solver = self.solve3
        else:
            raise RuntimeError("Error, inverse_solver must be either 'exact' "
                               "'approximate' or 'noinverse'")

        self.overlap = Overlap()

        ni = self.a_uci.shape[2]
        a_uci = np.empty((self.nmykpts, self.dim, ni + nsteps), self.wfs.dtype)
        b_uci = np.empty((self.nmykpts, self.dim, ni + nsteps), self.wfs.dtype)
        a_uci[:, :, :ni] = self.a_uci
        b_uci[:, :, :ni] = self.b_uci
        self.a_uci = a_uci
        self.b_uci = b_uci

        for u in range(self.nmykpts):
            for i in range(nsteps):
                self.step(u, ni + i)

    def step(self, u, i):
        print(u, i)
        integrate = self.wfs.gd.integrate
        w_cG = self.w_ucG[u]
        y_cG = self.y_ucG[u]
        wold_cG = self.wold_ucG[u]
        z_cG = self.z_cG

        self.solver(w_cG, self.z_cG, u)
        I_c = np.reshape(
            integrate(np.conjugate(z_cG) * w_cG)**-0.5, (self.dim, 1, 1, 1))
        z_cG *= I_c
        w_cG *= I_c

        if i != 0:
            b_c = 1.0 / I_c
        else:
            b_c = np.reshape(np.zeros(self.dim), (self.dim, 1, 1, 1))

        self.hamiltonian.apply(z_cG, y_cG, self.wfs, self.wfs.kpt_u[u])
        a_c = np.reshape(integrate(np.conjugate(z_cG) * y_cG),
                         (self.dim, 1, 1, 1))
        wnew_cG = (y_cG - a_c * w_cG - b_c * wold_cG)
        wold_cG[:] = w_cG
        w_cG[:] = wnew_cG
        self.a_uci[u, :, i] = a_c[:, 0, 0, 0]
        self.b_uci[u, :, i] = b_c[:, 0, 0, 0]

    def continued_fraction(self, e, k, c, i, imax):
        a_i = self.a_uci[k, c]
        b_i = self.b_uci[k, c]
        if i == imax - 2:
            return self.terminator(a_i[i], b_i[i], e)
        return 1.0 / (a_i[i] - e - b_i[i + 1]**2 *
                      self.continued_fraction(e, k, c, i + 1, imax))

    def get_spectra(self,
                    eps_s,
                    delta=0.1,
                    imax=None,
                    kpoint=None,
                    fwhm=None,
                    linbroad=None,
                    spin=0):
        assert not mpi.parallel

        # the following lines are to stop the user to make mistakes
        # if spin == 1:
        #     raise RuntimeError(
        #         'The core hole is always in spin 0: please use spin=0')

        n = len(eps_s)

        sigma_cn = np.zeros((self.dim, n))
        if imax is None:
            imax = self.a_uci.shape[2]
        eps_n = (eps_s + delta * 1.0j) / Hartree

        # if a certain k-point is chosen
        if kpoint is not None:
            for c in range(self.dim):
                sigma_cn[c] += self.continued_fraction(eps_n, kpoint, c, 0,
                                                       imax).imag
        else:
            for k in range(self.nkpts):
                print('kpoint', k, 'spin_k', self.spin_k[k], spin, 'weight',
                      self.weight_k[k])
                if self.spin_k[k] == spin:
                    weight = self.weight_k[k]
                    for c in range(self.dim):
                        sigma_cn[c] += weight * self.continued_fraction(
                            eps_n, k, c, 0, imax).imag

        if self.op_scc is not None:
            sigma0_cn = sigma_cn
            sigma_cn = np.zeros((self.dim, n))
            for op_cc in self.op_scc:
                sigma_cn += np.dot(op_cc**2, sigma0_cn)
            sigma_cn /= len(self.op_scc)

        # gaussian broadening
        if fwhm is not None:
            sigma_tmp = np.zeros(sigma_cn.shape)

            # constant broadening fwhm
            if linbroad is None:
                alpha = 4 * log(2) / fwhm**2
                for n, eps in enumerate(eps_s):
                    x = -alpha * (eps_s - eps)**2
                    x = np.clip(x, -100.0, 100.0)
                    sigma_tmp += np.outer(sigma_cn[:, n],
                                          (alpha / pi)**0.5 * np.exp(x))

            else:
                # constant broadening fwhm until linbroad[1] and a
                # constant broadening over linbroad[2] with fwhm2=
                # linbroad[0]
                fwhm2 = linbroad[0]
                lin_e1 = linbroad[1]
                lin_e2 = linbroad[2]
                for n, eps in enumerate(eps_s):
                    if eps < lin_e1:
                        alpha = 4 * log(2) / fwhm**2
                    elif eps <= lin_e2:
                        fwhm_lin = (fwhm + (eps - lin_e1) * (fwhm2 - fwhm) /
                                    (lin_e2 - lin_e1))
                        alpha = 4 * log(2) / fwhm_lin**2
                    elif eps >= lin_e2:
                        alpha = 4 * log(2) / fwhm2**2

                    x = -alpha * (eps_s - eps)**2
                    x = np.clip(x, -100.0, 100.0)
                    sigma_tmp += np.outer(sigma_cn[:, n],
                                          (alpha / pi)**0.5 * np.exp(x))
            sigma_cn = sigma_tmp

        return sigma_cn

    def solve(self, w_cG, z_cG, u):
        # exact inverse overlap
        self.overlap.apply_inverse(w_cG, self.tmp1_cG, self.wfs,
                                   self.wfs.kpt_u[u])
        self.u = u
        CG(self, z_cG, self.tmp1_cG, tolerance=self.tol, maxiter=self.maxiter)

    def solve2(self, w_cG, z_cG, u):
        # approximate inverse overlap
        self.overlap.apply_inverse(w_cG, z_cG, self.wfs, self.wfs.kpt_u[u])

        self.u = u

    def solve3(self, w_cG, z_cG, u):
        # no inverse overlap
        z_cG[:] = w_cG
        self.u = u

    def sum(self, a):
        self.wfs.gd.comm.sum(a)
        return a

    def __call__(self, in_cG, out_cG):
        """Function that is called by CG. It returns S~-1Sx_in in x_out
        """

        kpt = self.wfs.kpt_u[self.u]
        self.overlap.apply(in_cG, self.tmp2_cG, self.wfs, kpt)
        self.overlap.apply_inverse(self.tmp2_cG, out_cG, self.wfs, kpt)

    def terminator(self, a, b, e):
        """ Analytic formula to terminate the continued fraction from
        [R Haydock, V Heine, and M J Kelly,
        J Phys. C: Solid State Physics, Vol 8, (1975), 2591-2605]
        """

        return 0.5 * (e - a - ((e - a)**2 - 4 * b**2)**0.5 / b**2)

    def duplicate_coefficients(self, nsteps, ntimes):
        n1 = self.a_uci.shape[0]
        n2 = self.a_uci.shape[1]
        ni = self.a_uci.shape[2]
        type_code = self.a_uci.dtype.name  # typecode()
        a_uci = np.empty((n1, n2, ni + nsteps * ntimes), type_code)
        b_uci = np.empty((n1, n2, ni + nsteps * ntimes), type_code)
        a_uci[:, :, :ni] = self.a_uci
        b_uci[:, :, :ni] = self.b_uci

        ni1 = ni
        ni2 = ni + nsteps
        for i in range(ntimes):
            a_uci[:, :, ni1:ni2] = a_uci[:, :, ni - nsteps:ni]
            b_uci[:, :, ni1:ni2] = b_uci[:, :, ni - nsteps:ni]
            ni1 += nsteps
            ni2 += nsteps
        self.a_uci = a_uci
        self.b_uci = b_uci
Пример #12
0
class FDPWWaveFunctions(WaveFunctions):
    """Base class for finite-difference and planewave classes."""
    def __init__(self, diagksl, orthoksl, initksl, *args, **kwargs):
        WaveFunctions.__init__(self, *args, **kwargs)

        self.diagksl = diagksl
        self.orthoksl = orthoksl
        self.initksl = initksl

        self.set_orthonormalized(False)

        self.overlap = Overlap(orthoksl, self.timer)

    def set_setups(self, setups):
        WaveFunctions.set_setups(self, setups)
        if not self.gamma:
            self.pt.set_k_points(self.kd.ibzk_qc)

    def set_orthonormalized(self, flag):
        self.orthonormalized = flag

    def set_positions(self, spos_ac):
        WaveFunctions.set_positions(self, spos_ac)
        self.set_orthonormalized(False)
        self.pt.set_positions(spos_ac)
        self.allocate_arrays_for_projections(self.pt.my_atom_indices)
        self.positions_set = True

    def initialize(self, density, hamiltonian, spos_ac):
        if self.kpt_u[0].psit_nG is None:
            basis_functions = BasisFunctions(
                self.gd, [setup.phit_j for setup in self.setups], cut=True)
            if not self.gamma:
                basis_functions.set_k_points(self.kd.ibzk_qc)
            basis_functions.set_positions(spos_ac)
        elif isinstance(self.kpt_u[0].psit_nG, TarFileReference):
            self.initialize_wave_functions_from_restart_file()

        if self.kpt_u[0].psit_nG is not None:
            density.initialize_from_wavefunctions(self)
        elif density.nt_sG is None:
            density.initialize_from_atomic_densities(basis_functions)
            # Initialize GLLB-potential from basis function orbitals
            if hamiltonian.xc.type == 'GLLB':
                hamiltonian.xc.initialize_from_atomic_orbitals(basis_functions)
        else:  # XXX???
            # We didn't even touch density, but some combinations in paw.set()
            # will make it necessary to do this for some reason.
            density.calculate_normalized_charges_and_mix()
        hamiltonian.update(density)

        if self.kpt_u[0].psit_nG is None:
            self.initialize_wave_functions_from_basis_functions(
                basis_functions, density, hamiltonian, spos_ac)

    def initialize_wave_functions_from_basis_functions(self, basis_functions,
                                                       density, hamiltonian,
                                                       spos_ac):
        if 0:
            self.timer.start('Random wavefunction initialization')
            for kpt in self.kpt_u:
                kpt.psit_nG = self.gd.zeros(self.mynbands, self.dtype)
                if extra_parameters.get('sic'):
                    kpt.W_nn = np.zeros((self.nbands, self.nbands),
                                        dtype=self.dtype)
            self.random_wave_functions(0)
            self.timer.stop('Random wavefunction initialization')
            return

        self.timer.start('LCAO initialization')
        lcaoksl, lcaobd = self.initksl, self.initksl.bd
        lcaowfs = LCAOWaveFunctions(lcaoksl, self.gd, self.nvalence,
                                    self.setups, lcaobd, self.dtype,
                                    self.world, self.kd)
        lcaowfs.basis_functions = basis_functions
        lcaowfs.timer = self.timer
        self.timer.start('Set positions (LCAO WFS)')
        lcaowfs.set_positions(spos_ac)
        self.timer.stop('Set positions (LCAO WFS)')

        eigensolver = get_eigensolver('lcao', 'lcao')
        eigensolver.initialize(self.gd, self.dtype, self.setups.nao, lcaoksl)

        # XXX when density matrix is properly distributed, be sure to
        # update the density here also
        eigensolver.iterate(hamiltonian, lcaowfs)

        # Transfer coefficients ...
        for kpt, lcaokpt in zip(self.kpt_u, lcaowfs.kpt_u):
            kpt.C_nM = lcaokpt.C_nM

        # and get rid of potentially big arrays early:
        del eigensolver, lcaowfs

        self.timer.start('LCAO to grid')
        for kpt in self.kpt_u:
            kpt.psit_nG = self.gd.zeros(self.mynbands, self.dtype)
            if extra_parameters.get('sic'):
                kpt.W_nn = np.zeros((self.nbands, self.nbands),
                                    dtype=self.dtype)
            basis_functions.lcao_to_grid(kpt.C_nM,
                                         kpt.psit_nG[:lcaobd.mynbands], kpt.q)
            kpt.C_nM = None
        self.timer.stop('LCAO to grid')

        if self.mynbands > lcaobd.mynbands:
            # Add extra states.  If the number of atomic orbitals is
            # less than the desired number of bands, then extra random
            # wave functions are added.
            self.random_wave_functions(lcaobd.mynbands)
        self.timer.stop('LCAO initialization')

    def initialize_wave_functions_from_restart_file(self):
        if not isinstance(self.kpt_u[0].psit_nG, TarFileReference):
            return

        # Calculation started from a restart file.  Copy data
        # from the file to memory:
        for kpt in self.kpt_u:
            file_nG = kpt.psit_nG
            kpt.psit_nG = self.gd.empty(self.mynbands, self.dtype)
            if extra_parameters.get('sic'):
                kpt.W_nn = np.zeros((self.nbands, self.nbands),
                                    dtype=self.dtype)
            # Read band by band to save memory
            for n, psit_G in enumerate(kpt.psit_nG):
                if self.gd.comm.rank == 0:
                    big_psit_G = np.array(file_nG[n][:], self.dtype)
                else:
                    big_psit_G = None
                self.gd.distribute(big_psit_G, psit_G)

    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.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.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 orthonormalize(self):
        for kpt in self.kpt_u:
            self.overlap.orthonormalize(self, kpt)
        self.set_orthonormalized(True)

    def _get_wave_function_array(self, u, n):
        psit_nG = self.kpt_u[u].psit_nG
        if psit_nG is None:
            raise RuntimeError('This calculator has no wave functions!')
        return psit_nG[n][:]  # dereference possible tar-file content

    def write_wave_functions(self, writer):
        try:
            from gpaw.io.hdf5 import Writer as HDF5Writer
        except ImportError:
            hdf5 = False
        else:
            hdf5 = isinstance(writer, HDF5Writer)

        if self.world.rank == 0 or hdf5:
            writer.add(
                'PseudoWaveFunctions',
                ('nspins', 'nibzkpts', 'nbands', 'ngptsx', 'ngptsy', 'ngptsz'),
                dtype=self.dtype)

        if hdf5:
            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=True, *indices)
        else:
            for s in range(self.nspins):
                for k in range(self.nibzkpts):
                    for n in range(self.nbands):
                        psit_G = self.get_wave_function_array(n, k, s)
                        if self.world.rank == 0:
                            writer.fill(psit_G, s, k, n)

    def estimate_memory(self, mem):
        gridbytes = self.gd.bytecount(self.dtype)
        mem.subnode('Arrays psit_nG',
                    len(self.kpt_u) * self.mynbands * gridbytes)
        self.eigensolver.estimate_memory(mem.subnode('Eigensolver'), self.gd,
                                         self.dtype, self.mynbands,
                                         self.nbands)
        self.pt.estimate_memory(mem.subnode('Projectors'))
        self.matrixoperator.estimate_memory(mem.subnode('Overlap op'),
                                            self.dtype)