def test_add(self): file_path = Path.clean(self.data_path, 'small_file.txt') file = File(file_path) add_str = "string to add" right_full_str = file + add_str self.assertEqual(right_full_str, "Small file\n Very small \n\nstring to add") l_add_str = " left string to add" left_full_str = l_add_str + file self.assertEqual(left_full_str, " left string to addSmall file\n Very small \n\n") file_path_1 = Path.clean(self.data_path, 'small_file.txt') file_path_2 = Path.clean(self.data_path, 'small_file_2.txt') first_file = File(file_path_1) second_file = File(file_path_2) final_file = first_file + second_file self.assertEqual(final_file.lines, [ 'Small file', ' Very small ', '', '', 'Small file 2', ' Not as small ', '' ])
def get_sample(calculation_path): structure = Structure(file_path=Path.join(calculation_path, 'POSCAR')) structure.shift_sites_so_first_atom_is_at_origin() outcar = Outcar(file_path=Path.join(calculation_path, 'OUTCAR')) lattice_information = structure.get_magnitudes_and_angles() ideal_perovskite_structure = Perovskite( supercell_dimensions=[1, 1, 1], lattice=copy.deepcopy(structure.lattice), species_list=structure.get_species_list()) displacement_vector = DisplacementVector.get_instance_from_displaced_structure_relative_to_reference_structure( reference_structure=ideal_perovskite_structure, displaced_structure=structure, coordinate_mode='Cartesian') energy = outcar.energy forces = outcar.final_forces_list stresses = outcar.final_stresses_list volume = structure.lattice.get_volume() #in A^3 for z in range(len(stresses)): stresses[z] /= volume row_of_data = lattice_information + displacement_vector.to_list() + [ energy ] + forces + stresses output_string = ' '.join([str(x) for x in row_of_data]) return row_of_data, output_string
def test_init(self): with self.assertRaises(IOError): file = File(Path.clean(self.data_path, 'file.txt')) file = File() self.assertEqual(file.lines, []) self.assertEqual(file.load_path, None) with self.assertRaises(IOError): file.write_to_path() file_path = Path.clean(self.data_path, 'file1.txt') file = File(file_path) self.assertEqual(file.lines[0], "This is a test file") self.assertEqual(file.lines[4], "line 5") self.assertEqual(file.lines[6], "end of testing file") with self.assertRaises(IndexError): file.lines[7] self.assertEqual(file.load_path, file_path) file_path = Path.clean(self.data_path, 'small_file.txt') file = File(file_path) self.assertEqual(file.lines, ['Small file', ' Very small ', '']) file_path = Path.clean(self.data_path, 'empty.txt') file = File(file_path) self.assertEqual(file.lines, []) file_path = Path.clean(self.data_path, 'almost_empty.txt') file = File(file_path) #this file contains: line 1: '\n' line 2: '' self.assertEqual(file.lines, [''])
def __init__(self, path, structures_list, vasp_run_inputs_dictionary, wavecar_path=None): """ path should be the main path of the calculation set structures_list should be the set of structures for which forces are calculated. vasp_run_inputs_dictionary should look like: vasp_run_inputs_dictionary = { 'kpoint_scheme': 'Monkhorst', 'kpoint_subdivisions_list': [4, 4, 4], 'encut': 800, 'npar': 1 (optional) } wavecar_path should be the wavecar of a similar structure to the input structures of the structures_list. """ for structure in structures_list: Structure.validate(structure) self.path = path self.structures_list = structures_list self.vasp_run_inputs = copy.deepcopy(vasp_run_inputs_dictionary) self.wavecar_path = wavecar_path Path.make(path) self.initialize_vasp_runs()
def test_write_to_path(self): file_path = Path.clean(self.data_path, 'small_file.txt') file = File(file_path) file[0] += " for line 0" file[3] = "line 3" file += "" file += "here\nand here" file += "" self.assertEqual(file.lines, [ 'Small file for line 0', ' Very small ', '', 'line 3', '', 'here', 'and here', '' ]) file.write_to_path( Path.clean(self.data_path, 'small_file_ammended.txt')) file_2 = File(Path.clean(self.data_path, 'small_file_ammended.txt')) file_2[2] = "no more" file_2.write_to_path() file_3 = File(Path.clean(self.data_path, 'small_file_ammended.txt')) self.assertEqual(file_3.lines, [ 'Small file for line 0', ' Very small ', 'no more', 'line 3', '', 'here', 'and here', '' ])
def npar_converger(base_path, structure, npar_list, base_kpoints_scheme, base_kpoints_subdivisions_list, base_ediff, base_encut, node_count): """Takes in a structure, set of npars, and base params and runs set in base_path""" encut_convergence_set_path = Path.clean(base_path) Path.make(encut_convergence_set_path) for npar in npar_list: run_path = Path.join(encut_convergence_set_path, str(npar)) input_dictionary = { 'external_relaxation_count': 0, 'kpoint_schemes_list': [base_kpoints_scheme], 'kpoint_subdivisions_lists': [base_kpoints_subdivisions_list], 'submission_script_modification_keys_list': ['100'], 'submission_node_count_list': [node_count], 'ediff': [base_ediff], 'encut': [base_encut], 'npar': [npar] } vasp_relaxation = VaspRelaxation(run_path, structure, input_dictionary, verbose=False) if vasp_relaxation.update(): print "npar:", npar, "node_count:", node_count, round( vasp_relaxation.get_final_energy(True), 5), round(vasp_relaxation.total_time, 2) else: pass
def test_init(self): file_path = Path.clean(self.data_path, "kpt_1") kpoints = Kpoints(file_path) self.assertEqual(kpoints.scheme, 'Gamma') kpoints.scheme = "monkhorst" self.assertEqual(kpoints.scheme, 'Monkhorst') self.assertEqual(kpoints.subdivisions_list, [4, 2, 4]) kpoints.subdivisions_list = [6, 6, 8] self.assertEqual(kpoints.subdivisions_list, [6, 6, 8]) new_path = Path.clean(self.data_path, "new_kpt_1") kpoints.write_to_path(new_path) kpoints_2 = Kpoints(new_path) self.assertEqual(kpoints_2.subdivisions_list, [6, 6, 8]) self.assertEqual(kpoints.scheme, 'Monkhorst') with self.assertRaises(Exception): kpoints_2.scheme = "Lonkhorst" with self.assertRaises(Exception): kpoints_2.subdivisions_list = ['2', '4', '5', '6'] kpoints_3 = Kpoints(scheme_string="Gamma", subdivisions_list=[4, 6, 8]) self.assertEqual(str(kpoints_3), 'Kpoints File\n0\nGamma\n4 6 8\n0 0 0\n')
def __init__(self, path, initial_structure=None, input_dictionary=None): """ Input dicitonary should look something like: { 'external_relaxation_count': 4, 'kpoint_schemes_list': ['Gamma'], 'kpoint_subdivisions_lists': [[1, 1, 1], [1, 1, 2], [2, 2, 4]], 'submission_script_modification_keys_list': ['100', 'standard', 'standard_gamma'], #optional - will default to whatever queue adapter gives 'submission_node_count_list': [1, 2], 'ediff': [0.001, 0.00001, 0.0000001], 'encut': [200, 400, 600, 800], 'isif' : [5, 2, 3], 'calculation_type': 'gga' #not needed - defaults to 'lda', 'static_lwave': True #if set, lwave is left on for static run #any other incar parameters with value as a list } If no input_dictionary is provided, this class will attempt to load a saved pickled instance. """ self.path = Path.expand(path) if not input_dictionary: self.load() else: self.vasp_run_list = [] self.input_initial_structure = initial_structure Path.make(self.path) self.unpack_input_dictionary_into_self(input_dictionary) self.save() self.initialize_run_list()
def __init__(self, file_path=None, elements_list=None, basenames_list=None, calculation_type='lda_paw', minimal_form=None): super(Potcar, self).__init__(file_path) if file_path: if self.get_lines_containing_string("PAW_PBE"): #be careful if potcars different than used to in future self.calculation_type = 'gga_paw_pbe' else: self.calculation_type = 'lda_paw' if minimal_form: calculation_type = minimal_form['calculation_type'] basenames_list = minimal_form['basenames'] if elements_list or basenames_list: self.calculation_type = calculation_type element_mapping_file = File(Potcar.element_mapping_path) element_mapping_string = str(element_mapping_file) potcar_dict = json.loads(element_mapping_string) base_path = potcar_dict[calculation_type]['path'] if elements_list: potcar_paths = [Path.clean(base_path, potcar_dict[calculation_type][element], 'POTCAR') for element in elements_list] elif basenames_list: potcar_paths = [Path.clean(base_path, basename, 'POTCAR') for basename in basenames_list] concatenated_file = File() for path in potcar_paths: concatenated_file = concatenated_file + File(path) self.lines = concatenated_file.lines
def initialize_paths(self): """ Creates the base path directory and the first generation's path if they don't already exist. """ if not Path.exists(self.path): Path.make(self.path) if self.get_generation_count() == 0: Path.make(self.get_next_generation_path())
def __init__(self, path, initial_structure=None, relaxation_input_dictionary=None, extra_dos_inputs=None): """ Input dicitonary should look something like: { 'external_relaxation_count': 4, 'kpoint_schemes_list': ['Gamma'], 'kpoint_subdivisions_lists': [[1, 1, 1], [1, 1, 2], [2, 2, 4]], 'submission_script_modification_keys_list': ['100', 'standard', 'standard_gamma'], #optional - will default to whatever queue adapter gives 'submission_node_count_list': [1, 2], 'ediff': [0.001, 0.00001, 0.0000001], 'encut': [200, 400, 600, 800], 'isif' : [5, 2, 3], 'calculation_type': 'gga' #must be gga in this case #any other incar parameters with value as a list } extra_dos_inputs is optional and should look like: { HFSCREEN = 0.2 # sets the type of hybid - can give params for pbe0 here too NEDOS = 4001 'kpoint_schemes_list': ['Gamma'], 'kpoint_subdivisions_lists': [[2, 2, 4]], #for enhanced kpoints - can be up to three for each stage of the dos any other incar params for just dos part } If no relaxation_input_dictionary is provided, this class will attempt to load a saved pickled instance. """ self.path = Path.expand(path) self.relaxation_path = self.get_extended_path('relaxation') self.dos_path = self.get_extended_path('dos') self.extra_dos_inputs = extra_dos_inputs self.dos_runs_list = [] if 'calculation_type' not in relaxation_input_dictionary or relaxation_input_dictionary[ 'calculation_type'] != 'gga': raise Exception( "Calculation type must be gga for hybrid calculations") if not relaxation_input_dictionary: self.load() else: Path.make(self.path) relaxation_input_dictionary['static_lwave'] = True self.relaxation = VaspRelaxation( path=self.relaxation_path, initial_structure=initial_structure, input_dictionary=relaxation_input_dictionary) self.save()
def test_str(self): file = File(Path.clean(self.data_path, 'small_file.txt')) self.assertEqual(str(file), "Small file\n Very small \n\n") file = File(Path.clean(self.data_path, 'empty.txt')) self.assertEqual(str(file), "") file = File(Path.clean( self.data_path, 'almost_empty.txt')) #this file contains: line 1: '\n' line 2: '' self.assertEqual(str(file), "\n")
def get_structure_list(path): """loads in poscars at path and returns list of structures""" path = Path.clean(path) files = Path.get_list_of_files_at_path(path) structs = {} for file in files: structs[file] = Structure(Path.join(path, file)) return structs
def get_job_id_at_path(calculation_path): """ Looks in the .job_id file for an id. Returns id as a string if present, None if not present """ id_path = Path.join(calculation_path, QueueAdapter.id_path) if Path.exists(id_path): return File(id_path)[0] else: return None
def append_individuals_at_path(self, path): """ Looks for individuals inside path (saved as directories like 'individual_1, individual_2, ...') and appends to self.individuals """ #put all valid basenames in list like like: [individual_1, individual_2, ...] elligible_directory_basenames = Path.get_list_of_directory_basenames_containing_string( path, Population.individual_prefix_string) for basename in elligible_directory_basenames: self.individuals.append( self.directory_to_individual_conversion_method( Path.join(path, basename)))
def initialize_vasp_runs(self): """ Creates any force calculation vasp runs (static force calculations at .../0, .../1, ...) that do not already exist. """ if Path.exists(self.get_extended_path('0')): #we don't want to write more runs if any already exist return for i, structure in enumerate(self.structures_list): run_path = self.get_extended_path(str(i)) if not Path.exists(run_path): self.create_new_vasp_run(run_path, structure)
def update(self): """ Main update method - create individuals until quota is reached, update the individuals in the current generation, create next generation path if current generation is complete. """ self.populate_current_generation() generation_complete = self.update_all_individuals_of_current_generation( ) if generation_complete and ( self.population_collection.get_generation_count() < self.ga_driver.get_max_number_of_generations()): Path.make(self.population_collection.get_next_generation_path())
def complete(self): for misfit_strain in self.misfit_strains_list: misfit_path = self.get_extended_path(str(misfit_strain).replace('-', 'n')) for i in range(10000): relax_path = Path.join(misfit_path, 'structure_' + str(i)) if not Path.exists(relax_path): return True else: relaxation = VaspRelaxation(path=relax_path) if not relaxation.complete: return False
def get_next_available_individual_path(self, generation_directory_path): if not Path.exists(generation_directory_path): raise Exception("Generation path does not exist") i = 1 while True: individual_path = Path.join( generation_directory_path, Population.individual_prefix_string + str(i)) if not Path.exists(individual_path): return individual_path i += 1
def initialize_run_list(self): """sets self.vasp_run_list based on directories present""" self.vasp_run_list = [] for i in range(self.external_relaxation_count): run_path = self.get_extended_path(VaspRelaxation.external_relax_basename_string + str(i+1)) if Path.exists(run_path): self.vasp_run_list.append(VaspRun(run_path)) else: return static_path = self.get_extended_path(VaspRelaxation.static_basename_string) if Path.exists(static_path): self.vasp_run_list.append(VaspRun(static_path))
def update(self): Path.make(self.path) self.vasp_static_run_sets_list = [] for expansion_term in self.taylor_expansion.expansion_terms_list: vasp_static_run_set = self.get_vasp_static_run_set(expansion_term) if vasp_static_run_set.complete: self.set_taylor_coefficient(vasp_static_run_set, expansion_term) vasp_static_run_set.delete_wavecars_of_completed_runs() else: vasp_static_run_set.update()
def __init__(self, path, reference_structure=None, distorted_structure=None, vasp_run_inputs_dictionary=None): """ reference_structure should be a Structure instance with the same lattice as distorted structure. Usually this reference is chosen to be centrosymmetry (like ideal perovskite) so that absolute polarizations of the distorted structure can be caluclated. distorted_structure should be a Structure instance with the same lattice as the reference structure, but some of the atoms shifted to cause a change in polarization. vasp_run_inputs_dictionary should look like: vasp_run_inputs_dictionary = { 'kpoint_scheme': 'Monkhorst', 'kpoint_subdivisions_list': [4, 4, 4], 'encut': 800, } """ self.path = Path.expand(path) if (reference_structure == None) or (distorted_structure == None) or (vasp_run_inputs_dictionary == None): self.load() else: Structure.validate(reference_structure) Structure.validate(distorted_structure) if not reference_structure.lattice.equals( distorted_structure.lattice): raise Exception( "Warning: It's very difficult to interpret polarization results when the lattices of the reference and distorted structures are not equal. This is likely an error.", reference_structure.lattice, distorted_structure.lattice) self.reference_structure = reference_structure self.distorted_structure = distorted_structure self.vasp_run_inputs = copy.deepcopy(vasp_run_inputs_dictionary) self.vasp_run_list = [] self.save() Path.make(path) self.initialize_vasp_runs()
def write_parent_structures_to_poscar_files(self): if self.parent_structures_list and (not Path.exists( self.get_extended_path(".parent_paths"))): for i, parent_structure in enumerate(self.parent_structures_list): parent_structure.to_poscar_file_path( self.get_extended_path('.parent_poscar_' + str(i) + '.vasp'))
def write_error_to_path(calculation_path, error_string): error_path = Path.join( calculation_path, QueueAdapter.error_path + "_" + su.get_time_stamp_string()) file = File() file[0] = error_string file.write_to_path(error_path)
def test_init(self): file_path = Path.clean(self.data_path, "poscar_small") poscar = Poscar(file_path) self.assertEqual(poscar.species_list, ['Si', 'O']) self.assertEqual(poscar.lines, [ 'Poscar', '1.0', '5.0 0.2 0.1', '0.4\t 6.0 0.7', '-0.2 0.0 7.7 ', 'Si O', '2 1', 'Direct', '0.11 0.22 0.33', '0.33 0.22 0.11', '0.22 0.33 0.11 ' ]) self.assertEqual(poscar.species_count_list, [2, 1]) self.assertEqual(poscar.coordinate_mode, 'Direct') self.assertEqual( poscar.coordinates, [[0.11, 0.22, 0.33], [0.33, 0.22, 0.11], [0.22, 0.33, 0.11]]) lattice = [[2.2, 2.3, 2.1], [1.2, 3.3, 0.0], [-1.2, -2.2, 4.4]] species_list = ['K', 'V', 'O'] species_count_list = [1, 2, 3] coordinate_mode = 'cart' coordinates = [[0.2, 0.3, 0.4], [0.5, 0.5, 0.1], [-0.01, 0.1, 0.01], [2.33, 6.5, 3.2], [0.0, 0.1, -0.1], [0.1, 0.5, 0.5]] poscar = Poscar(None, lattice, species_list, species_count_list, coordinate_mode, coordinates) self.assertEqual(poscar.species_list, ['K', 'V', 'O']) self.assertEqual(poscar.lines, [ 'Poscar', '1.0', '2.2 2.3 2.1', '1.2 3.3 0.0', '-1.2 -2.2 4.4', 'K V O', '1 2 3', 'Cartesian', '0.2 0.3 0.4', '0.5 0.5 0.1', '-0.01 0.1 0.01', '2.33 6.5 3.2', '0.0 0.1 -0.1', '0.1 0.5 0.5' ]) self.assertEqual(poscar.species_count_list, [1, 2, 3]) self.assertEqual(poscar.coordinate_mode, 'Cartesian') self.assertEqual(poscar.coordinates, coordinates)
def structure_is_duplicate(self, structure, misfit_path): """ Returns true if this has been the initial structure for any previous relaxation """ for i in range(10000): relax_path = Path.join(misfit_path, 'structure_' + str(i)) if not Path.exists(relax_path): return False else: comparison_structure = Structure(file_path=Path.join(relax_path, 'original_initial_structure')) if structure.is_equivalent_to_structure(comparison_structure): print "FOUND DUPLICATE in epitaxial_relaxer.py" return True
def validate_constructor_arguments(file_path, lattice, sites): Path.validate(path=file_path, allow_none=True) if file_path == None: if lattice == None: raise Exception("A lattice must be specified.") else: Lattice.validate_lattice_representation(lattice) if not sites: raise Exception( "A sites list or SiteColleciton instance must be specified." ) else: SiteCollection.validate_sites(sites)
def __init__(self, path=None, calculation_set=None, structure_creation_id_string=None, parent_structures_list=None, parent_paths_list=None): if not calculation_set: if not path: raise Exception( "Path must be given if no calculation set is provided.") self.path = Path.expand(path) self.load() else: self.path = calculation_set.path self.calculation_set = calculation_set self.structure_creation_id_string = structure_creation_id_string if structure_creation_id_string else self.get_structure_creation_id_string( ) self.parent_structures_list = parent_structures_list if parent_structures_list else self.get_parent_structures_list( ) self.parent_paths_list = parent_paths_list if parent_paths_list else self.get_parent_paths_list( ) self.write_structure_creation_id_string_to_file( ) #store how this individual was made self.write_parent_structures_to_poscar_files() self.write_parent_paths_to_file() self.save()
def __init__(self, path, initial_structures_list, reference_structure, vasp_relaxation_inputs_dictionary, reference_lattice_constant, misfit_strains_list, supercell_dimensions_list, calculate_polarizations=False): """ path should be the main path of the calculation set initial_structures_list should be the set of structures that are relaxed at each misfit strain reference structure can have any lattice but its atom positions must be in direct coords as the positions to compare polarizations to (choose a centrosymmetric structure if possible) vasp_relaxation_inputs_dictionary should look something like: { 'external_relaxation_count': 4, 'kpoint_schemes_list': ['Gamma'], 'kpoint_subdivisions_lists': [[1, 1, 1], [1, 1, 2], [2, 2, 4]], 'submission_script_modification_keys_list': ['100', 'standard', 'standard_gamma'], #optional - will default to whatever queue adapter gives 'submission_node_count_list': [1, 2], 'ediff': [0.001, 0.00001, 0.0000001], 'encut': [200, 400, 600, 800], 'isif' : [5, 2, 3] #any other incar parameters with value as a list } reference_lattice_constant should be the lattice constant a0 which, when multiplied by the list of misfit strains, generates the new in-plane lattice constant at those strains. For each lattice constant and each structure, a relaxation is performed. Then, the lowest energy structures at each misfit strain can be determined, and a convex hull results. """ for structure in initial_structures_list: Structure.validate(structure) basic_validators.validate_real_number(reference_lattice_constant) for misfit_strain in misfit_strains_list: basic_validators.validate_real_number(misfit_strain) self.path = path self.initial_structures_list = initial_structures_list self.reference_structure = reference_structure self.vasp_relaxation_inputs_dictionary = vasp_relaxation_inputs_dictionary self.reference_lattice_constant = reference_lattice_constant self.misfit_strains_list = misfit_strains_list self.supercell_dimensions_list = supercell_dimensions_list self.calculate_polarizations = calculate_polarizations Path.make(path) self.initialize_vasp_relaxations()
def __init__(self, path, structure=None, incar=None, kpoints=None, potcar=None, submission_script_file=None, input_set=None, wavecar_path=None, chargecar_path=None): """ Cases for __init__: 1. path does not exist or is empty => make the directory, enforce input file arguments all exists, write out input files to directory 2. path exists and is not empty 1. path/.job_id does not exist 1. path has all 5 input files written to it already => do nothing if not all five input parameters exist, else overwrite current input files to directory 2. path does not have all 5 input files (has some subset or none) => enforce input file arguments all exists, write out input files to directory 2. path/.job_id exists => do nothing """ self.path = Path.clean(path) if input_set: structure = input_set.structure incar = input_set.incar kpoints = input_set.kpoints potcar = input_set.potcar submission_script_file = input_set.submission_script_file all_essential_input_parameters_exist = not bool(filter(lambda x: x == None, [structure, incar, potcar, submission_script_file])) if not Path.exists(self.path) or Path.is_empty(self.path): if not all_essential_input_parameters_exist: raise Exception("All five vasp input files must be input for run to be initialized.") else: Path.make(self.path) self.write_input_files_to_path(structure, incar, kpoints, potcar, submission_script_file, wavecar_path, chargecar_path) else: if self.job_id_string: pass else: if self.all_input_files_are_present(): #all input files are written to directory if all_essential_input_parameters_exist: #overwrite what's there self.write_input_files_to_path(structure, incar, kpoints, potcar, submission_script_file, wavecar_path, chargecar_path) else: pass #do nothing - don't have the necessary inputs to start a run else: #not all input files currently exist - must have necessary input params to overwrite if not all_essential_input_parameters_exist: raise Exception("All five vasp input files must be input for run with incomplete inputs at path to be initialized.") else: self.write_input_files_to_path(structure, incar, kpoints, potcar, submission_script_file, wavecar_path)