예제 #1
0
    def run(self):
        """Run the vibration calculations.

        This will calculate the forces for 6 displacements per atom +/-x,
        +/-y, +/-z. Only those calculations that are not already done will be
        started. Be aware that an interrupted calculation may produce an empty
        file (ending with .pckl), which must be deleted before restarting the
        job. Otherwise the forces will not be calculated for that
        displacement.

        Note that the calculations for the different displacements can be done
        simultaneously by several independent processes. This feature relies
        on the existence of files and the subsequent creation of the file in
        case it is not found.
        """

        filename = self.name + '.eq.pckl'
        fd = opencew(filename)
        if fd is not None:
            self.calculate(filename, fd)

        p = self.atoms.positions.copy()
        for a in self.indices:
            for i in range(3):
                for sign in [-1, 1]:
                    for ndis in range(1, self.nfree // 2 + 1):
                        filename = ('%s.%d%s%s.pckl' %
                                    (self.name, a, 'xyz'[i],
                                     ndis * ' +-'[sign]))
                        fd = opencew(filename)
                        if fd is not None:
                            disp = ndis * sign * self.delta
                            self.atoms.positions[a, i] = p[a, i] + disp
                            self.calculate(filename, fd)
                            self.atoms.positions[a, i] = p[a, i]
예제 #2
0
    def run(self):
        """Run the vibration calculations.

        This will calculate the forces for 6 displacements per atom +/-x,
        +/-y, +/-z. Only those calculations that are not already done will be
        started. Be aware that an interrupted calculation may produce an empty
        file (ending with .pckl), which must be deleted before restarting the
        job. Otherwise the forces will not be calculated for that
        displacement.

        Note that the calculations for the different displacements can be done
        simultaneously by several independent processes. This feature relies
        on the existence of files and the subsequent creation of the file in
        case it is not found.
        """

        filename = self.name + '.eq.pckl'
        fd = opencew(filename)
        if fd is not None:
            self.calculate(filename, fd)

        p = self.atoms.positions.copy()
        for filename, a, i, disp in self.displacements():
            fd = opencew(filename)
            if fd is not None:
                self.atoms.positions[a, i] = p[a, i] + disp
                self.calculate(filename, fd)
                self.atoms.positions[a, i] = p[a, i]
예제 #3
0
def numeric_forces(atoms, indices=None, axes=(0, 1, 2), d=0.001,
                   parallel=None, name=None):
    """Evaluate finite-difference forces on several atoms.

    Returns an array of forces for each specified atomic index and
    each specified axis, calculated using finite difference on each
    atom and direction separately.  Array has same shape as if
    returned from atoms.get_forces(); uncalculated elements are zero.

    Calculates all forces by default."""

    if indices is None:
        indices = range(len(atoms))
    F_ai = np.zeros_like(atoms.positions)
    n = len(indices) * len(axes)
    if parallel is None:
        atom_tasks = [atoms] * n
        master = True
        calc_comm = world
    else:
        calc_comm, tasks_comm, tasks_rank = distribute_cpus(parallel, world)
        master = calc_comm.rank == 0
        calculator = atoms.get_calculator()
        calculator.set(communicator=calc_comm)
        atom_tasks = [None] * n
        for i in range(n):
            if ((i - tasks_rank) % tasks_comm.size) == 0:
                atom_tasks[i] = atoms
    for ia, a in enumerate(indices):
        for ii, i in enumerate(axes):
            atoms = atom_tasks[ia * len(axes) + ii]
            if atoms is not None:
                done = 0
                if name:
                    fname = '%s.%d%s.pckl' % (name, a, 'xyz'[i])
                    fd = opencew(fname, calc_comm)
                    if fd is None:
                        if master:
                            try:
                                F_ai[a, i] = pickle.load(open(fname))
                                print '# atom', a, 'xyz'[i], 'done'
                                done = 1
                            except EOFError:
                                pass
                        done = calc_comm.sum(done)
                if not done:
                    print '# rank', rank, 'calculating atom', a, 'xyz'[i]
                    force = numeric_force(atoms, a, i, d)
                    if master:
                        F_ai[a, i] = force
                        if name:
                            fd = open('%s.%d%s.pckl' % (name, a, 'xyz'[i]),
                                      'w')
                            pickle.dump(force, fd)
                            fd.close()
    if parallel is not None:
        world.sum(F_ai)
    return F_ai
예제 #4
0
파일: task.py 프로젝트: hess8/pythonscripts
    def run(self, names):
        """Run task far all names.

        The task will be one of these four:

        * Open ASE's GUI
        * Write configuration to file
        * Write summary
        * Do the actual calculation
        """

        names = self.expand(names)
        names = names[self.slice]
        names = self.exclude(names)

        if self.gui:
            for name in names:
                view(self.create_system(name))
            return

        if self.write_to_file:
            if self.write_to_file[0] == ".":
                for name in names:
                    filename = self.get_filename(name, self.write_to_file)
                    write(filename, self.create_system(name))
            else:
                assert len(names) == 1
                write(self.write_to_file, self.create_system(names[0]))
            return

        if self.write_summary:
            self.read(names)
            self.analyse()
            self.summarize(names)
            return

        atoms = None
        for name in names:
            if self.use_lock_files:
                lockfilename = self.get_filename(name, ".json")
                fd = opencew(lockfilename)
                if fd is None:
                    self.log("Skipping", name)
                    continue
                fd.close()
            atoms = self.run_single(name)

        return atoms
예제 #5
0
파일: g0w0.py 프로젝트: robwarm/gpaw-symm
 def calculate_exact_exchange(self):
     name = self.filename + '.exx.npy'
     fd = opencew(name)
     if fd is None:
         print('Reading EXX contribution from file:', name, file=self.fd)
         with open(name) as fd:
             self.exx_sin = np.load(fd)
         assert self.exx_sin.shape == self.shape, self.exx_sin.shape
         return
         
     print('Calculating EXX contribution', file=self.fd)
     exx = EXX(self.calc, kpts=self.kpts, bands=self.bands,
               txt=self.filename + '.exx.txt', timer=self.timer)
     exx.calculate()
     self.exx_sin = exx.get_eigenvalue_contributions() / Hartree
     np.save(fd, self.exx_sin)
예제 #6
0
파일: g0w0.py 프로젝트: robwarm/gpaw-symm
 def calculate_ks_xc_contribution(self):
     name = self.filename + '.vxc.npy'
     fd = opencew(name)
     if fd is None:
         print('Reading Kohn-Sham XC contribution from file:', name,
               file=self.fd)
         with open(name) as fd:
             self.vxc_sin = np.load(fd)
         assert self.vxc_sin.shape == self.shape, self.vxc_sin.shape
         return
         
     print('Calculating Kohn-Sham XC contribution', file=self.fd)
     vxc_skn = vxc(self.calc, self.calc.hamiltonian.xc) / Hartree
     n1, n2 = self.bands
     self.vxc_sin = vxc_skn[:, self.kpts, n1:n2]
     np.save(fd, self.vxc_sin)
예제 #7
0
    def run(self):
        """Run the calculations for the required displacements.

        This will do a calculation for 6 displacements per atom, +-x, +-y, and
        +-z. Only those calculations that are not already done will be
        started. Be aware that an interrupted calculation may produce an empty
        file (ending with .pckl), which must be deleted before restarting the
        job. Otherwise the calculation for that displacement will not be done.

        """

        # Atoms in the supercell -- repeated in the lattice vector directions
        # beginning with the last
        atoms_N = self.atoms * self.N_c
        
        # Set calculator if provided
        assert self.calc is not None, "Provide calculator in __init__ method"
        atoms_N.set_calculator(self.calc)
        
        # Do calculation on equilibrium structure
        filename = self.name + '.eq.pckl'

        fd = opencew(filename)
        if fd is not None:
            # Call derived class implementation of __call__
            output = self.__call__(atoms_N)
            # Write output to file
            if rank == 0:
                pickle.dump(output, fd)
                sys.stdout.write('Writing %s\n' % filename)
                fd.close()
            sys.stdout.flush()

        # Positions of atoms to be displaced in the reference cell
        natoms = len(self.atoms)
        offset = natoms * self.offset
        pos = atoms_N.positions[offset: offset + natoms].copy()
        
        # Loop over all displacements
        for a in self.indices:
            for i in range(3):
                for sign in [-1, 1]:
                    # Filename for atomic displacement
                    filename = '%s.%d%s%s.pckl' % \
                               (self.name, a, 'xyz'[i], ' +-'[sign])
                    # Wait for ranks before checking for file
                    # barrier()
                    fd = opencew(filename)
                    if fd is None:
                        # Skip if already done
                        continue

                    # Update atomic positions
                    atoms_N.positions[offset + a, i] = \
                        pos[a, i] + sign * self.delta
                    
                    # Call derived class implementation of __call__
                    output = self.__call__(atoms_N)
                    # Write output to file
                    if rank == 0:
                        pickle.dump(output, fd)
                        sys.stdout.write('Writing %s\n' % filename)
                        fd.close()
                    sys.stdout.flush()
                    # Return to initial positions
                    atoms_N.positions[offset + a, i] = pos[a, i]
예제 #8
0
relativistic = "scalar"

linspace = (0.98, 1.02, 5)  # eos numpy's linspace
linspacestr = "".join([str(t) + "x" for t in linspace])[:-1]

code = "aims" + "-" + basis + "_e" + linspacestr
code = code + "_k" + str(kptdensity) + "_w" + str(width)
code = code + "_t" + str(basis_threshold) + "_r" + str(relativistic)

collection = Collection()

for name in names:
    # save all steps in one traj file in addition to the database
    # we should only used the database c.reserve, but here
    # traj file is used as another lock ...
    fd = opencew(name + "_" + code + ".traj")
    if fd is None:
        continue
    traj = PickleTrajectory(name + "_" + code + ".traj", "w")
    atoms = collection[name]
    cell = atoms.get_cell()
    kpts = tuple(kpts2mp(atoms, kptdensity, even=True))
    kwargs = {}
    if relativistic == "scalar":
        kwargs.update({"relativistic": ["atomic_zora", relativistic]})
    elif relativistic == "none":
        kwargs.update({"relativistic": "none"})
    else:  # e.g. 1.0e-12
        kwargs.update({"relativistic": ["zora", relativistic]})
    if atoms.get_initial_magnetic_moments().any():  # spin-polarization
        magmom = atoms.get_initial_magnetic_moments().sum() / len(atoms)
        'addgrid':True,
        'lwave':False,
        'setups': setups,
        'lscalapack':False,
    },
}

linspace = (0.500,0.600,0.700,0.800,0.850,0.900,0.925,0.950,0.975,1.000,1.025,1.050,1.075,1.100,1.125,1.150,1.175,1.200,1.250,1.300,1.350,1.400,1.500)
#linspace = (0.700,0.800,0.850,0.900,0.925,0.950,0.975,1.000,1.025,1.050,1.075,1.100,1.125,1.150,1.175,1.200)

for name in elements:
    # save all steps in one traj file in addition to the database
    # we should only used the database c.reserve, but here
    # traj file is used as another lock ...
    label = code + '_k' + str(kptdensity) + '_w' + str(width)
    fd = opencew(name + '_' + label + '.traj')
    if fd is None:
        continue
    traj = PickleTrajectory(name + '_' + label + '.traj', 'w')
    if name in ['Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr']:
        cr = 1.69
    else:
        cr = covalent_radii[atomic_numbers[name]]
    if structure == 'fcc':
        atoms = bulk(name, crystalstructure='fcc',
                     a=structures[name][structure])
        # sum of covelent radii
        scr = cr * 2
    elif structure == 'rocksalt':
        atoms = bulk(name + 'O', crystalstructure='rocksalt',
                     a=structures[name][structure])
code = code + '_k' + str(kptdensity) + '_w' + str(width)
code = code + '_r' + str(relativistic)

for name in D.keys() + names:  # adsorbates + surfaces elements
    for category in ['fcc111', 'fcc']:
        for adsorbate in ['', 'C', 'O']:
            if category == 'fcc111':
                compound = '%s%s-%s' % (name, adsorbate, category)
            else:
                if category == 'fcc' and adsorbate != '':
                    continue
                else:
                    compound = '%s-%s' % (name, category)
            label = compound + '_' + code
            # but here traj file is used as another lock ...
            fd = opencew(label + '.traj')
            if fd is None:
                continue
            traj = PickleTrajectory(label + '.traj', 'w')
            a = fcc[name]
            if category == 'fcc':
                atoms = bulk(name, 'fcc', a=a)
                site = ''
            else:
                atoms = fcc111(name, size=(2, 2, 4), a=a, vacuum=6.0)
                atoms.center(axis=2)
                site = ''
                if adsorbate != '':
                    d = D[adsorbate][name]['d']
                    site = D[adsorbate][name]['site']
                    add_adsorbate(atoms, adsorbate, d, site)
예제 #11
0
    def numeric_forces(self,atoms, axes=(0, 1, 2), d=0.001,
                       parallel=None, name=None):
        """Evaluate finite-difference forces on several atoms.

        Returns an array of forces for each specified atomic index and
        each specified axis, calculated using finite difference on each
        atom and direction separately.  Array has same shape as if
        returned from atoms.get_forces(); uncalculated elements are zero.

        Calculates all forces by default."""

        import numpy as np
        from ase.parallel import world, rank, distribute_cpus
        from ase.utils import opencew

        indices = range(len(atoms))
        F_ai = np.zeros_like(atoms.positions)
        n = len(indices) * len(axes)
        total_calculation = len(indices)*len(axes)

        if parallel is None:
            atom_tasks = [atoms] * n
            master = True
            calc_comm = world
        else:
            calc_comm, tasks_comm, tasks_rank = distribute_cpus(parallel, world)
            master = calc_comm.rank == 0
            calculator = atoms.get_calculator()
            calculator.set(communicator=calc_comm)
            atom_tasks = [None] * n
            for i in range(n):
                if ((i - tasks_rank) % tasks_comm.size) == 0:
                    atom_tasks[i] = atoms
        counter = 0
        for ia, a in enumerate(indices):
            for ii, i in enumerate(axes):
                atoms = atom_tasks[ia * len(axes) + ii]
                if atoms is not None:
                    done = 0
                    if name:
                        fname = '%s.%d%s.pckl' % (name, a, 'xyz'[i])
                        fd = opencew(fname, calc_comm)
                        if fd is None:
                            if master:
                                try:
                                    F_ai[a, i] = pickle.load(open(fname))
                                    print '# atom', a, 'xyz'[i], 'done'
                                    done = 1
                                except EOFError:
                                    pass
                            done = calc_comm.sum(done)
                    if not done:
                        # print '# rank', rank, 'calculating atom', a, 'xyz'[i]
                        force = self.__numeric_force(atoms, a, i, d)
                        if master:
                            F_ai[a, i] = force
                            if name:
                                fd = open('%s.%d%s.pckl' % (name, a, 'xyz'[i]),
                                          'w')
                                pickle.dump(force, fd)
                                fd.close()
                counter += 1
                fan = ['-', '\\', '|', '/']
                sys.stderr.write("\r[%-100s]%3.1f%% %1s" % tuple([int(float(counter)/float(total_calculation)*100)*'=',float(counter)/float(total_calculation)*100,fan[counter%4]]))
                sys.stderr.flush()
        if parallel is not None:
            world.sum(F_ai)
        return F_ai
else:
    linspace = (0.92, 1.08, 7)  # eos numpy's linspace
if category == 'magnetic_moments':
    linspace = (1.0, 1.0, 1)  # eos numpy's linspace
linspacestr = ''.join([str(t) + 'x' for t in linspace])[:-1]

code = category + '_gpaw' + '-' + mode + str(e) + '_c' + str(constant_basis)
code = code + '_e' + linspacestr
code = code + '_k' + str(kptdensity) + '_w' + str(width)
code = code + '_r' + str(relativistic)

for name in names:
    # save all steps in one traj file in addition to the database
    # we should only used the database c.reserve, but here
    # traj file is used as another lock ...
    fd = opencew(name + '_' + code + '.traj')
    if fd is None:
        continue
    traj = Trajectory(name + '_' + code + '.traj', 'w')
    atoms = collection[name]
    cell = atoms.get_cell()
    kpts = tuple(kpts2mp(atoms, kptdensity, even=True))
    kwargs = {}
    if mode == 'fd':
        if constant_basis:
            # gives more smooth EOS in fd mode
            kwargs.update({'gpts': h2gpts(e, cell)})
        else:
            kwargs.update({'h': e})
    elif mode == 'pw':
        if constant_basis:
예제 #13
0
    def calculate(self):
        calc = self.calc
        focc_S = self.focc_S
        e_S = self.e_S
        op_scc = calc.wfs.kd.symmetry.op_scc

        # Get phi_qaGp
        if self.mode == 'RPA':
            self.phi_aGp = self.get_phi_aGp()
        else:
            fd = opencew('phi_qaGp')
            if fd is None:
                self.reader = Reader('phi_qaGp')
                tmp = self.load_phi_aGp(self.reader, 0)[0]
                assert len(tmp) == self.npw
                self.printtxt('Finished reading phi_aGp')
            else:
                self.printtxt('Calculating phi_qaGp')
                self.get_phi_qaGp()
                world.barrier()
                self.reader = Reader('phi_qaGp')                
            self.printtxt('Memory used %f M' % (maxrss() / 1024.**2))
            self.printtxt('')

        if self.optical_limit:
            iq = np.where(np.sum(abs(self.ibzq_qc), axis=1) < 1e-5)[0][0]
        else:
            iq = np.where(np.sum(abs(self.ibzq_qc - self.q_c), axis=1) < 1e-5)[0][0]
        kc_G = np.array([self.V_qGG[iq, iG, iG] for iG in range(self.npw)])
        if self.optical_limit:
            kc_G[0] = 0.

        # Get screened Coulomb kernel
        if self.mode == 'BSE':
            try:
                # Read
                data = pickle.load(open(self.kernel_file+'.pckl'))
                W_qGG = data['W_qGG']
                assert np.shape(W_qGG) == np.shape(self.V_qGG)
                self.printtxt('Finished reading screening interaction kernel')
            except:
                # Calculate from scratch
                self.printtxt('Calculating screening interaction kernel.')
                W_qGG = self.full_static_screened_interaction()
            self.printtxt('')
        else:
            W_qGG = self.V_qGG
 
        t0 = time()
        self.printtxt('Calculating %s matrix elements' % self.mode)

        # Calculate full kernel
        K_SS = np.zeros((self.nS_local, self.nS), dtype=complex)
        self.rhoG0_S = np.zeros(self.nS, dtype=complex)

        #noGmap = 0
        for iS in range(self.nS_start, self.nS_end):
            k1, n1, m1 = self.Sindex_S3[iS]
            rho1_G = self.density_matrix(n1,m1,k1)
            self.rhoG0_S[iS] = rho1_G[0]
            for jS in range(self.nS):
                k2, n2, m2 = self.Sindex_S3[jS]
                rho2_G = self.density_matrix(n2,m2,k2)
                K_SS[iS-self.nS_start, jS] = np.sum(rho1_G.conj() * rho2_G * kc_G)

                if not self.mode == 'RPA':
                    rho3_G = self.density_matrix(n1,n2,k1,k2)
                    rho4_G = self.density_matrix(m1,m2,self.kq_k[k1],
                                                 self.kq_k[k2])

                    q_c = self.kd.bzk_kc[k2] - self.kd.bzk_kc[k1]
                    q_c[np.where(q_c > 0.501)] -= 1.
                    q_c[np.where(q_c < -0.499)] += 1.
                    iq = self.kd.where_is_q(q_c, self.bzq_qc)
                    
                    if not self.qsymm:    
                        W_GG = W_qGG[iq]
                    else:
                        ibzq = self.ibzq_q[iq]
                        W_GG_tmp = W_qGG[ibzq]

                        iop = self.iop_q[iq]
                        timerev = self.timerev_q[iq]
                        diff_c = self.diff_qc[iq]
                        invop = np.linalg.inv(op_scc[iop])
                        Gindex = np.zeros(self.npw, dtype=int)
                        for iG in range(self.npw):
                            G_c = self.Gvec_Gc[iG]
                            if timerev:
                                RotG_c = -np.int8(np.dot(invop, G_c+diff_c).round())
                            else:
                                RotG_c = np.int8(np.dot(invop, G_c+diff_c).round())
                            tmp_G = np.abs(self.Gvec_Gc - RotG_c).sum(axis=1)
                            try:
                                Gindex[iG] = np.where(tmp_G < 1e-5)[0][0]
                            except:
                                #noGmap += 1
                                Gindex[iG] = -1
    
                        W_GG = np.zeros_like(W_GG_tmp)
                        for iG in range(self.npw):
                            for jG in range(self.npw):
                                if Gindex[iG] == -1 or Gindex[jG] == -1:
                                    W_GG[iG, jG] = 0
                                else:
                                    W_GG[iG, jG] = W_GG_tmp[Gindex[iG], Gindex[jG]]
                                    
                    if self.mode == 'BSE':
                        tmp_GG = np.outer(rho3_G.conj(), rho4_G) * W_GG
                        K_SS[iS-self.nS_start, jS] -= 0.5 * np.sum(tmp_GG)
                    else:
                        tmp_G = rho3_G.conj() * rho4_G * np.diag(W_GG)
                        K_SS[iS-self.nS_start, jS] -= 0.5 * np.sum(tmp_G)
            self.timing(iS, t0, self.nS_local, 'pair orbital') 
 
        K_SS /= self.vol

        world.sum(self.rhoG0_S)
        #self.printtxt('Number of G indices outside the Gvec_Gc: %d' % noGmap)

        # Get and solve Hamiltonian
        H_sS = np.zeros_like(K_SS)
        for iS in range(self.nS_start, self.nS_end):
            H_sS[iS-self.nS_start,iS] = e_S[iS]
            for jS in range(self.nS):
                H_sS[iS-self.nS_start,jS] += focc_S[iS] * K_SS[iS-self.nS_start,jS]
  
        # Force matrix to be Hermitian
        if not self.coupling:
            if world.size > 1:
                H_Ss = self.redistribute_H(H_sS)
            else:
                H_Ss = H_sS
            H_sS = (np.real(H_sS) + np.real(H_Ss.T)) / 2. + 1j * (np.imag(H_sS) - np.imag(H_Ss.T)) /2.

        # Save H_sS matrix
        self.par_save('H_SS','H_SS', H_sS)

        return H_sS
예제 #14
0
    def calculate_screened_potential(self):
        """Calculates the screened potential for each q-point in the 1st BZ.
        Since many q-points are related by symmetry, the actual calculation is
        only done for q-points in the IBZ and the rest are obtained by symmetry
        transformations. Results are returned as a generator to that it is not
        necessary to store a huge matrix for each q-point in the memory."""
        # The decorator $timer('W') doesn't work for generators, do we will
        # have to manually start and stop the timer here:
        self.timer.start('W')
        print('Calculating screened Coulomb potential', file=self.fd)
        if self.wstc:
            print('Using Wigner-Seitz truncated Coloumb potential',
                  file=self.fd)
            
        if self.ppa:
            print('Using Godby-Needs plasmon-pole approximation:',
                  file=self.fd)
            print('    Fitting energy: i*E0, E0 = %.3f Hartee' % self.E0,
                  file=self.fd)

            # use small imaginary frequency to avoid dividing by zero:
            frequencies = [1e-10j, 1j * self.E0 * Hartree]
            
            parameters = {'eta': 0,
                          'hilbert': False,
                          'timeordered': False,
                          'frequencies': frequencies}
        else:
            print('Using full frequency integration:', file=self.fd)
            print('  domega0: {0:g}'.format(self.domega0 * Hartree),
                  file=self.fd)
            print('  omega2: {0:g}'.format(self.omega2 * Hartree),
                  file=self.fd)

            parameters = {'eta': self.eta * Hartree,
                          'hilbert': True,
                          'timeordered': True,
                          'domega0': self.domega0 * Hartree,
                          'omega2': self.omega2 * Hartree}
        
        chi0 = Chi0(self.calc,
                    nbands=self.nbands,
                    ecut=self.ecut * Hartree,
                    intraband=False,
                    real_space_derivatives=False,
                    txt=self.filename + '.w.txt',
                    timer=self.timer,
                    keep_occupied_states=True,
                    nblocks=self.blockcomm.size,
                    no_optical_limit=self.wstc,
                    **parameters)

        if self.wstc:
            wstc = WignerSeitzTruncatedCoulomb(
                self.calc.wfs.gd.cell_cv,
                self.calc.wfs.kd.N_c,
                chi0.fd)
        else:
            wstc = None
        
        self.omega_w = chi0.omega_w
        self.omegamax = chi0.omegamax
        
        htp = HilbertTransform(self.omega_w, self.eta, gw=True)
        htm = HilbertTransform(self.omega_w, -self.eta, gw=True)

        # Find maximum size of chi-0 matrices:
        gd = self.calc.wfs.gd
        nGmax = max(count_reciprocal_vectors(self.ecut, gd, q_c)
                    for q_c in self.qd.ibzk_kc)
        nw = len(self.omega_w)
        
        size = self.blockcomm.size
        mynGmax = (nGmax + size - 1) // size
        mynw = (nw + size - 1) // size
        
        # Allocate memory in the beginning and use for all q:
        A1_x = np.empty(nw * mynGmax * nGmax, complex)
        A2_x = np.empty(max(mynw * nGmax, nw * mynGmax) * nGmax, complex)
        
        # Need to pause the timer in between iterations
        self.timer.stop('W')
        for iq, q_c in enumerate(self.qd.ibzk_kc):
            self.timer.start('W')
            if self.savew:
                wfilename = self.filename + '.w.q%d.pckl' % iq
                fd = opencew(wfilename)
            if self.savew and fd is None:
                # Read screened potential from file
                with open(wfilename) as fd:
                    pd, W = pickle.load(fd)
            else:
                # First time calculation
                pd, W = self.calculate_w(chi0, q_c, htp, htm, wstc, A1_x, A2_x)
                if self.savew:
                    pickle.dump((pd, W), fd, pickle.HIGHEST_PROTOCOL)

            self.timer.stop('W')
            # Loop over all k-points in the BZ and find those that are related
            # to the current IBZ k-point by symmetry
            Q1 = self.qd.ibz2bz_k[iq]
            done = set()
            for s, Q2 in enumerate(self.qd.bz2bz_ks[Q1]):
                if Q2 >= 0 and Q2 not in done:
                    s = self.qd.sym_k[Q2]
                    self.s = s
                    self.U_cc = self.qd.symmetry.op_scc[s]
                    time_reversal = self.qd.time_reversal_k[Q2]
                    self.sign = 1 - 2 * time_reversal
                    Q_c = self.qd.bzk_kc[Q2]
                    d_c = self.sign * np.dot(self.U_cc, q_c) - Q_c
                    assert np.allclose(d_c.round(), d_c)
                    yield pd, W, Q_c
                    done.add(Q2)
예제 #15
0
    def run(self):
        """Run the calculations for the required displacements.

        This will do a calculation for 6 displacements per atom, +-x, +-y, and
        +-z. Only those calculations that are not already done will be
        started. Be aware that an interrupted calculation may produce an empty
        file (ending with .pckl), which must be deleted before restarting the
        job. Otherwise the calculation for that displacement will not be done.

        """

        # Atoms in the supercell -- repeated in the lattice vector directions
        # beginning with the last
        atoms_N = self.atoms * self.N_c

        # Set calculator if provided
        assert self.calc is not None, "Provide calculator in __init__ method"
        atoms_N.calc = self.calc

        # Do calculation on equilibrium structure
        self.state = 'eq.pckl'
        filename = self.name + '.' + self.state

        fd = opencew(filename)
        if fd is not None:
            # Call derived class implementation of __call__
            output = self.__call__(atoms_N)
            # Write output to file
            if world.rank == 0:
                pickle.dump(output, fd, protocol=2)
                sys.stdout.write('Writing %s\n' % filename)
                fd.close()
            sys.stdout.flush()

        # Positions of atoms to be displaced in the reference cell
        natoms = len(self.atoms)
        offset = natoms * self.offset
        pos = atoms_N.positions[offset:offset + natoms].copy()

        # Loop over all displacements
        for a in self.indices:
            for i in range(3):
                for sign in [-1, 1]:
                    # Filename for atomic displacement
                    self.state = '%d%s%s.pckl' % (a, 'xyz'[i], ' +-'[sign])
                    filename = self.name + '.' + self.state
                    # Wait for ranks before checking for file
                    # barrier()
                    fd = opencew(filename)
                    if fd is None:
                        # Skip if already done
                        continue

                    # Update atomic positions
                    atoms_N.positions[offset + a, i] = \
                        pos[a, i] + sign * self.delta

                    # Call derived class implementation of __call__
                    output = self.__call__(atoms_N)
                    # Write output to file
                    if world.rank == 0:
                        pickle.dump(output, fd, protocol=2)
                        sys.stdout.write('Writing %s\n' % filename)
                        fd.close()
                    sys.stdout.flush()
                    # Return to initial positions
                    atoms_N.positions[offset + a, i] = pos[a, i]