def apply_transformation(self, structure, return_ranked_list=False): """ Return either a single ordered structure or a sequence of all ordered structures. Args: structure: Structure to order. return_ranked_list (bool): Whether or not multiple structures are returned. If return_ranked_list is a number, that number of structures is returned. Returns: Depending on returned_ranked list, either a transformed structure or a list of dictionaries, where each dictionary is of the form {"structure" = .... , "other_arguments"} The list of ordered structures is ranked by ewald energy / atom, if the input structure is an oxidation state decorated structure. Otherwise, it is ranked by number of sites, with smallest number of sites first. """ try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if structure.is_ordered: raise ValueError("Enumeration can be carried out only on " "disordered structures!") if self.refine_structure: finder = SymmetryFinder(structure, self.symm_prec) structure = finder.get_refined_structure() contains_oxidation_state = False for sp in structure.composition.elements: if hasattr(sp, "oxi_state") and sp.oxi_state != 0: contains_oxidation_state = True break adaptor = EnumlibAdaptor(structure, min_cell_size=self.min_cell_size, max_cell_size=self.max_cell_size, symm_prec=self.symm_prec, refine_structure=False) adaptor.run() structures = adaptor.structures original_latt = structure.lattice inv_latt = np.linalg.inv(original_latt.matrix) ewald_matrices = {} all_structures = [] for s in structures: new_latt = s.lattice transformation = np.dot(new_latt.matrix, inv_latt) transformation = tuple([tuple([int(round(cell)) for cell in row]) for row in transformation]) if contains_oxidation_state: if transformation not in ewald_matrices: s_supercell = Structure.from_sites(structure.sites) s_supercell.make_supercell(transformation) ewald = EwaldSummation(s_supercell) ewald_matrices[transformation] = ewald else: ewald = ewald_matrices[transformation] energy = ewald.compute_sub_structure(s) all_structures.append({"num_sites": len(s), "energy": energy, "structure": s}) else: all_structures.append({"num_sites": len(s), "structure": s}) def sort_func(s): return s["energy"] / s["num_sites"] if contains_oxidation_state \ else s["num_sites"] self._all_structures = sorted(all_structures, key=sort_func) if return_ranked_list: return self._all_structures[0:num_to_return] else: return self._all_structures[0]["structure"]
def apply_transformation(self, structure, return_ranked_list=False): """ Return either a single ordered structure or a sequence of all ordered structures. Args: structure: Structure to order. return_ranked_list (bool): Whether or not multiple structures are returned. If return_ranked_list is a number, that number of structures is returned. Returns: Depending on returned_ranked list, either a transformed structure or a list of dictionaries, where each dictionary is of the form {"structure" = .... , "other_arguments"} The list of ordered structures is ranked by ewald energy / atom, if the input structure is an oxidation state decorated structure. Otherwise, it is ranked by number of sites, with smallest number of sites first. """ try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if self.occu_tol: species = [dict(d) for d in structure.species_and_occu] # Here, we rescale all occupancies such that they meet the frac # limit. for sp in species: for k, v in sp.items(): sp[k] = float(Fraction(v).limit_denominator(self.occu_tol)) structure = Structure(structure.lattice, species, structure.frac_coords) if self.refine_structure: finder = SpacegroupAnalyzer(structure, self.symm_prec) structure = finder.get_refined_structure() contains_oxidation_state = all( [hasattr(sp, "oxi_state") and sp.oxi_state != 0 for sp in structure.composition.elements] ) if structure.is_ordered: warn("Enumeration skipped for structure with composition {} " "because it is ordered".format(structure.composition)) structures = [structure.copy()] else: adaptor = EnumlibAdaptor( structure, min_cell_size=self.min_cell_size, max_cell_size=self.max_cell_size, symm_prec=self.symm_prec, refine_structure=False, enum_precision_parameter=self.enum_precision_parameter, check_ordered_symmetry=self.check_ordered_symmetry) adaptor.run() structures = adaptor.structures original_latt = structure.lattice inv_latt = np.linalg.inv(original_latt.matrix) ewald_matrices = {} all_structures = [] for s in structures: new_latt = s.lattice transformation = np.dot(new_latt.matrix, inv_latt) transformation = tuple([tuple([int(round(cell)) for cell in row]) for row in transformation]) if contains_oxidation_state: if transformation not in ewald_matrices: s_supercell = structure * transformation ewald = EwaldSummation(s_supercell) ewald_matrices[transformation] = ewald else: ewald = ewald_matrices[transformation] energy = ewald.compute_sub_structure(s) all_structures.append({"num_sites": len(s), "energy": energy, "structure": s}) else: all_structures.append({"num_sites": len(s), "structure": s}) def sort_func(s): return s["energy"] / s["num_sites"] if contains_oxidation_state \ else s["num_sites"] self._all_structures = sorted(all_structures, key=sort_func) if return_ranked_list: return self._all_structures[0:num_to_return] else: return self._all_structures[0]["structure"]
def apply_transformation(self, structure, return_ranked_list=False): """ Return either a single ordered structure or a sequence of all ordered structures. Args: structure: Structure to order. return_ranked_list (bool): Whether or not multiple structures are returned. If return_ranked_list is a number, that number of structures is returned. Returns: Depending on returned_ranked list, either a transformed structure or a list of dictionaries, where each dictionary is of the form {"structure" = .... , "other_arguments"} The list of ordered structures is ranked by ewald energy / atom, if the input structure is an oxidation state decorated structure. Otherwise, it is ranked by number of sites, with smallest number of sites first. """ try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if structure.is_ordered: raise ValueError("Enumeration can be carried out only on " "disordered structures!") if self.refine_structure: finder = SpacegroupAnalyzer(structure, self.symm_prec) structure = finder.get_refined_structure() contains_oxidation_state = all([ hasattr(sp, "oxi_state") and sp.oxi_state != 0 for sp in structure.composition.elements ]) adaptor = EnumlibAdaptor( structure, min_cell_size=self.min_cell_size, max_cell_size=self.max_cell_size, symm_prec=self.symm_prec, refine_structure=False, enum_precision_parameter=self.enum_precision_parameter, check_ordered_symmetry=self.check_ordered_symmetry) adaptor.run() structures = adaptor.structures original_latt = structure.lattice inv_latt = np.linalg.inv(original_latt.matrix) ewald_matrices = {} all_structures = [] for s in structures: new_latt = s.lattice transformation = np.dot(new_latt.matrix, inv_latt) transformation = tuple([ tuple([int(round(cell)) for cell in row]) for row in transformation ]) if contains_oxidation_state: if transformation not in ewald_matrices: s_supercell = Structure.from_sites(structure.sites) s_supercell.make_supercell(transformation) ewald = EwaldSummation(s_supercell) ewald_matrices[transformation] = ewald else: ewald = ewald_matrices[transformation] energy = ewald.compute_sub_structure(s) all_structures.append({ "num_sites": len(s), "energy": energy, "structure": s }) else: all_structures.append({"num_sites": len(s), "structure": s}) def sort_func(s): return s["energy"] / s["num_sites"] if contains_oxidation_state \ else s["num_sites"] self._all_structures = sorted(all_structures, key=sort_func) if return_ranked_list: return self._all_structures[0:num_to_return] else: return self._all_structures[0]["structure"]
def apply_transformation(self, structure, return_ranked_list=False): """ Return either a single ordered structure or a sequence of all ordered structures. Args: structure: Structure to order. return_ranked_list (bool): Whether or not multiple structures are returned. If return_ranked_list is a number, that number of structures is returned. Returns: Depending on returned_ranked list, either a transformed structure or a list of dictionaries, where each dictionary is of the form {"structure" = .... , "other_arguments"} The list of ordered structures is ranked by ewald energy / atom, if the input structure is an oxidation state decorated structure. Otherwise, it is ranked by number of sites, with smallest number of sites first. """ try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if self.refine_structure: finder = SpacegroupAnalyzer(structure, self.symm_prec) structure = finder.get_refined_structure() contains_oxidation_state = all([ hasattr(sp, "oxi_state") and sp.oxi_state != 0 for sp in structure.composition.elements ]) structures = None if structure.is_ordered: warn("Enumeration skipped for structure with composition {} " "because it is ordered".format(structure.composition)) structures = [structure.copy()] if self.max_disordered_sites: ndisordered = sum([1 for site in structure if not site.is_ordered]) if ndisordered > self.max_disordered_sites: raise ValueError("Too many disordered sites! ({} > {})".format( ndisordered, self.max_disordered_sites)) max_cell_sizes = range( self.min_cell_size, int(math.floor(self.max_disordered_sites / ndisordered)) + 1) else: max_cell_sizes = [self.max_cell_size] for max_cell_size in max_cell_sizes: adaptor = EnumlibAdaptor( structure, min_cell_size=self.min_cell_size, max_cell_size=max_cell_size, symm_prec=self.symm_prec, refine_structure=False, enum_precision_parameter=self.enum_precision_parameter, check_ordered_symmetry=self.check_ordered_symmetry, timeout=self.timeout) try: adaptor.run() except EnumError: warn("Unable to enumerate for max_cell_size = %d".format( max_cell_size)) structures = adaptor.structures if structures: break if structures is None: raise ValueError("Unable to enumerate") original_latt = structure.lattice inv_latt = np.linalg.inv(original_latt.matrix) ewald_matrices = {} all_structures = [] for s in structures: new_latt = s.lattice transformation = np.dot(new_latt.matrix, inv_latt) transformation = tuple([ tuple([int(round(cell)) for cell in row]) for row in transformation ]) if contains_oxidation_state and self.sort_criteria == "ewald": if transformation not in ewald_matrices: s_supercell = structure * transformation ewald = EwaldSummation(s_supercell) ewald_matrices[transformation] = ewald else: ewald = ewald_matrices[transformation] energy = ewald.compute_sub_structure(s) all_structures.append({ "num_sites": len(s), "energy": energy, "structure": s }) else: all_structures.append({"num_sites": len(s), "structure": s}) def sort_func(s): return s["energy"] / s["num_sites"] \ if contains_oxidation_state and self.sort_criteria == "ewald" \ else s["num_sites"] self._all_structures = sorted(all_structures, key=sort_func) if return_ranked_list: return self._all_structures[0:num_to_return] else: return self._all_structures[0]["structure"]
def apply_transformation(self, structure, return_ranked_list=False): """ Return either a single ordered structure or a sequence of all ordered structures. Args: structure: Structure to order. return_ranked_list (bool): Whether or not multiple structures are returned. If return_ranked_list is a number, that number of structures is returned. Returns: Depending on returned_ranked list, either a transformed structure or a list of dictionaries, where each dictionary is of the form {"structure" = .... , "other_arguments"} The list of ordered structures is ranked by ewald energy / atom, if the input structure is an oxidation state decorated structure. Otherwise, it is ranked by number of sites, with smallest number of sites first. """ try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if self.refine_structure: finder = SpacegroupAnalyzer(structure, self.symm_prec) structure = finder.get_refined_structure() contains_oxidation_state = all( [hasattr(sp, "oxi_state") and sp.oxi_state != 0 for sp in structure.composition.elements] ) structures = None if structure.is_ordered: warn("Enumeration skipped for structure with composition {} " "because it is ordered".format(structure.composition)) structures = [structure.copy()] if self.max_disordered_sites: ndisordered = sum([1 for site in structure if not site.is_ordered]) if ndisordered > self.max_disordered_sites: raise ValueError( "Too many disordered sites! ({} > {})".format( ndisordered, self.max_disordered_sites)) max_cell_sizes = range(self.min_cell_size, int( math.floor(self.max_disordered_sites / ndisordered)) + 1) else: max_cell_sizes = [self.max_cell_size] for max_cell_size in max_cell_sizes: adaptor = EnumlibAdaptor( structure, min_cell_size=self.min_cell_size, max_cell_size=max_cell_size, symm_prec=self.symm_prec, refine_structure=False, enum_precision_parameter=self.enum_precision_parameter, check_ordered_symmetry=self.check_ordered_symmetry, timeout=self.timeout) try: adaptor.run() except EnumError: warn("Unable to enumerate for max_cell_size = %d".format( max_cell_size)) structures = adaptor.structures if structures: break if structures is None: raise ValueError("Unable to enumerate") original_latt = structure.lattice inv_latt = np.linalg.inv(original_latt.matrix) ewald_matrices = {} all_structures = [] for s in structures: new_latt = s.lattice transformation = np.dot(new_latt.matrix, inv_latt) transformation = tuple([tuple([int(round(cell)) for cell in row]) for row in transformation]) if contains_oxidation_state and self.sort_criteria == "ewald": if transformation not in ewald_matrices: s_supercell = structure * transformation ewald = EwaldSummation(s_supercell) ewald_matrices[transformation] = ewald else: ewald = ewald_matrices[transformation] energy = ewald.compute_sub_structure(s) all_structures.append({"num_sites": len(s), "energy": energy, "structure": s}) else: all_structures.append({"num_sites": len(s), "structure": s}) def sort_func(s): return s["energy"] / s["num_sites"] \ if contains_oxidation_state and self.sort_criteria == "ewald" \ else s["num_sites"] self._all_structures = sorted(all_structures, key=sort_func) if return_ranked_list: return self._all_structures[0:num_to_return] else: return self._all_structures[0]["structure"]