def __init__( self, structure: Structure, energy: float, correction: float = 0.0, composition: Composition = None, energy_adjustments: list = None, parameters: dict = None, data: dict = None, entry_id: object = None, ): """ Initializes a ComputedStructureEntry. Args: structure (Structure): The actual structure of an entry. energy (float): Energy of the entry. Usually the final calculated energy from VASP or other electronic structure codes. energy_adjustments: An optional list of EnergyAdjustment to be applied to the energy. This is used to modify the energy for certain analyses. Defaults to None. parameters: An optional dict of parameters associated with the entry. Defaults to None. data: An optional dict of any additional data associated with the entry. Defaults to None. entry_id: An optional id to uniquely identify the entry. """ if composition: composition = Composition(composition) if ( composition.get_integer_formula_and_factor()[0] != structure.composition.get_integer_formula_and_factor()[0] ): raise ValueError("Mismatching composition provided.") else: composition = structure.composition super().__init__( composition, energy, correction=correction, energy_adjustments=energy_adjustments, parameters=parameters, data=data, entry_id=entry_id, ) self._structure = structure
def _composition_prototype(composition): """ Guess the phase prototype from the integer anonymized_composition. Args: composition (str): a given composition. Returns: prototype: double_perovskites: 1 unknown: 0 ...to be continued """ c = Composition(composition) c_int = Composition(c.get_integer_formula_and_factor()[0]) f_int_anynomous = c_int.anonymized_formula prototype = 0 if f_int_anynomous is "ABCDE6" and Element("O") in Composition( composition).elements: prototype = 1 # to be continued return prototype
def get_ionic_properties(row): # getting oxidation state of fractional formula is not implemented yet in pymatgen # round the fractional formular to 1 decimal place in order to speed up guessed_oxidation_state calculation in pymatgen # sum of fractions is preserved (=1) elem_frac = {row.A1:row.A1_frac, row.A2:row.A2_frac, row.B1:row.B1_frac, row.B2:row.B2_frac, row.O:row.O_frac} # _=elem_frac.pop('_', None) elem_frac_red = { k:v for k, v in elem_frac.items() if (v<1 and v>0)} # remove empty cation and oxygen anion # ceil and floor to 1 decimal places and create list frac_list=[(k,math.ceil(v*10)/10.0) if v==min(list(elem_frac_red.values())) else (k,math.floor(v*10)/10.0) for k, v in elem_frac_red.items()] frac_dict = {k:v for k,v in frac_list} elem_frac_copy = elem_frac.copy() # make a copy so that original element fractions are not updated elem_frac_copy.update(frac_dict) # update the dictionary with 1 decimal precision {Element: fraction} where fraction ceiled/floored for 1 decimal place # get fractional formula with 1 decimal point rounded fractions l=[] [l.append(k+str(v)) for k,v in elem_frac_copy.items() if k!='_'][0] formula_1deci = ''.join(l) comp = Composition(formula_1deci) # create pymatgen Composition object int_comp = Composition(comp.get_integer_formula_and_factor()[0]) # get integer formular elem_ionic_radius = {} # try: if len(int_comp.oxi_state_guesses())>0: ox_state_dict = int_comp.oxi_state_guesses()[0] # get the best oxidation state guess / pymatgen outputs fractional oxidation states where necessary for (elem,ox_st) in list(ox_state_dict.items()): if not ox_st.is_integer() or ox_st not in ElementSym(elem).ox_st_dict[elem]: avg_ionic_radius = get_avg_ionic_radius(elem, int(int_comp.get(elem)), ox_st) if avg_ionic_radius == -1: # oxidation states cannot be solved with all available oxidation states break elem_ionic_radius[elem] = avg_ionic_radius else: ionic_radius = ElementSym(elem).ionic_radii(ox_st) elem_ionic_radius[elem] = ionic_radius if len(elem_ionic_radius)==4: # now update the first elem_frac dict with the found ionic radius values (some oinic radii may be averages because of fractional oxidation state) elem_radii = elem_frac.copy() # for clarity elem_radii.update(elem_ionic_radius) rA_avg = (elem_frac[row.A1]*elem_radii[row.A1] + elem_frac[row.A2]*elem_radii[row.A2]) rB_avg = (elem_frac[row.B1]*elem_radii[row.B1] + elem_frac[row.B2]*elem_radii[row.B2]) rO = ElementSym('O').ionic_radii(-2) # oxygen's oxidation state is always -2 ox_st_dict_copy = elem_frac.copy() # to find nA, nB, nO ox_st_dict_copy.update(ox_state_dict) nA = elem_frac[row.A1]*ox_st_dict_copy[row.A1] + elem_frac[row.A2]*ox_st_dict_copy[row.A2] nB = elem_frac[row.B1]*ox_st_dict_copy[row.B1] + elem_frac[row.B2]*ox_st_dict_copy[row.B2] nO = -2 # Oxygent oxidation state # to make it easy to understand that these materials are discarded, the else statements are added below // not necessary if Ra_avg, Rb_avg etc. were initialized with -1 at the top else: rA_avg = -1 # discard these materials / oxidation states could not be solved by the algorithm rB_avg = -1 rO = ElementSym('O').ionic_radii(-2) nA = -1 nB = -1 nO = -2 # Oxygen oxidation state else: rA_avg = -1 # discard these materials where the ions show unknown oxidation states/ typically higher that the max oxi_state of a particular element rB_avg = -1 # pymatgen's oxi_state_guesses() couldn't solve these even with fractional oxidation states rO = ElementSym('O').ionic_radii(-2) nA = -1 # discard nB = -1 # discard nO = -2 # Oxygent oxidation state return nA, nB, nO, rA_avg, rB_avg, rO
def query( self, formula: str = Query( ..., description="Human readable chemical formula.", ), limit: int = Query( 10, description="Maximum number of matches to show. Defaults to 10.", ), ) -> STORE_PARAMS: self.formula = formula self.limit = limit try: comp = Composition(formula) except CompositionError: raise HTTPException( status_code=400, detail="Invalid formula provided.", ) ind_str = [] eles = [] if len(comp) == 1: d = comp.get_integer_formula_and_factor() s = d[0] + str(int(d[1])) if d[1] != 1 else d[0] ind_str.append(s) eles.append(d[0]) else: comp_red = comp.reduced_composition.items() for (i, j) in comp_red: if j != 1: ind_str.append(i.name + str(int(j))) else: ind_str.append(i.name) eles.append(i.name) final_terms = ["".join(entry) for entry in permutations(ind_str)] pipeline = [ { "$search": { "index": "formula_autocomplete", "text": { "path": "formula_pretty", "query": final_terms }, } }, { "$project": { "_id": 0, "formula_pretty": 1, "elements": 1, "length": { "$strLenCP": "$formula_pretty" }, } }, { "$match": { "length": { "$gte": len(final_terms[0]) }, "elements": { "$all": eles }, } }, { "$limit": limit }, { "$sort": { "length": 1 } }, { "$project": { "elements": 0, "length": 0 } }, ] return {"pipeline": pipeline}