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
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