def create_organism(self, id_generator, composition_space, constraints,
                        random):
        """
        Creates an organism for the initial population from a poscar or cif
        file.

        Returns an organism, or None if one could not be created.

        Args:
            id_generator: the IDGenerator used to assign id numbers to all
                organisms

            composition_space: the CompositionSpace of the search

            constraints: the Constraints of the search

            random: a copy of Python's built in PRNG

        TODO: the last three arguments are never actually used in this method,
            but I included them so the method has the same arguments as
            RandomOrganismCreator.create_organism() to allow the
            create_organism method to be called on both RandomOrganismCreator
            and FileOrganismCreator without having to know in advance which one
            it is. Maybe there's a better way to deal with this...
        """

        if self.files[self.num_made - 1].endswith('.cif') or self.files[
                self.num_made - 1].startswith('POSCAR'):
            try:
                new_cell = Cell.from_file(
                    str(self.path_to_folder) + '/' +
                    str(self.files[self.num_made - 1]))
                new_org = Organism(new_cell, id_generator, self.name,
                                   composition_space)
                print('Making organism {} from file: {} '.format(
                    new_org.id, self.files[self.num_made - 1]))
                self.update_status()
                return new_org
            except:
                print('Error reading structure from file: {} '.format(
                    self.files[self.num_made - 1]))
                self.update_status()
                return None
        else:
            print('File {} has invalid extension - file must end with .cif or '
                  'begin with POSCAR '.format(self.files[self.num_made - 1]))
            self.update_status()
            return None
    def get_cells(self):
        """
        Creates cells from the files and puts them in a list.

        Returns the list of Cell objects.

        Used for checking if all the composition space endpoint are included
        for phase diagram searches.
        """

        file_cells = []
        for cell_file in self.files:
            if cell_file.endswith('.cif') or cell_file.startswith('POSCAR'):
                try:
                    new_cell = Cell.from_file(
                        str(self.path_to_folder) + "/" + str(cell_file))
                    file_cells.append(new_cell)
                except:
                    pass
        return file_cells
Example #3
0
    def do_energy_calculation(self, organism, dictionary, key,
                              composition_space):
        """
        Calculates the energy of an organism using VASP, and stores the relaxed
        organism in the provided dictionary at the provided key. If the
        calculation fails, stores None in the dictionary instead.

        Args:
            organism: the Organism whose energy we want to calculate

            dictionary: a dictionary in which to store the relaxed Organism

            key: the key specifying where to store the relaxed Organism in the
                dictionary

            composition_space: the CompositionSpace of the search

        Precondition: the garun directory and temp subdirectory exist, and we
            are currently located inside the garun directory

        TODO: maybe use the custodian package for error handling
        """

        # make the job directory
        job_dir_path = str(os.getcwd()) + '/temp/' + str(organism.id)
        os.mkdir(job_dir_path)

        # copy the INCAR and KPOINTS files to the job directory
        shutil.copy(self.incar_file, job_dir_path)
        shutil.copy(self.kpoints_file, job_dir_path)

        # sort the organism's cell and write to POSCAR file
        organism.cell.sort()
        organism.cell.to(fmt='poscar', filename=job_dir_path + '/POSCAR')

        # get a list of the element symbols in the sorted order
        symbols = []
        for site in organism.cell.sites:
            if site.specie.symbol not in symbols:
                symbols.append(site.specie.symbol)

        # write the POTCAR file by concatenating the appropriate elemental
        # POTCAR files
        total_potcar_path = job_dir_path + '/POTCAR'
        with open(total_potcar_path, 'w') as total_potcar_file:
            for symbol in symbols:
                with open(self.potcar_files[symbol], 'r') as potcar_file:
                    for line in potcar_file:
                        total_potcar_file.write(line)

        # run 'callvasp' script as a subprocess to run VASP
        print('Starting VASP calculation on organism {} '.format(organism.id))
        devnull = open(os.devnull, 'w')
        try:
            subprocess.call(['callvasp', job_dir_path],
                            stdout=devnull,
                            stderr=devnull)
        except:
            print('Error running VASP on organism {} '.format(organism.id))
            dictionary[key] = None
            return

        # parse the relaxed structure from the CONTCAR file
        try:
            relaxed_cell = Cell.from_file(job_dir_path + '/CONTCAR')
        except:
            print('Error reading structure of organism {} from CONTCAR '
                  'file '.format(organism.id))
            dictionary[key] = None
            return

        # check if the VASP calculation converged
        converged = False
        with open(job_dir_path + '/OUTCAR') as f:
            for line in f:
                if 'reached' in line and 'required' in line and \
                        'accuracy' in line:
                    converged = True
        if not converged:
            print('VASP relaxation of organism {} did not converge '.format(
                organism.id))
            dictionary[key] = None
            return

        # parse the internal energy and pV (if needed) and compute the enthalpy
        pv = 0
        with open(job_dir_path + '/OUTCAR') as f:
            for line in f:
                if 'energy(sigma->0)' in line:
                    u = float(line.split()[-1])
                elif 'enthalpy' in line:
                    pv = float(line.split()[-1])
        enthalpy = u + pv

        organism.cell = relaxed_cell
        organism.total_energy = enthalpy
        organism.epa = enthalpy / organism.cell.num_sites
        print('Setting energy of organism {} to {} '
              'eV/atom '.format(organism.id, organism.epa))
        dictionary[key] = organism