class Compound(object): """ Compound class Attributes (of subclass compete_compound and host_compound): del_Hf = enthalpy of formation formula (string) = chemical formula for compound, e.g., LiPO4 """ def __init__(self,del_Hf=0.00,formula=''): self.del_Hf=del_Hf self.formula=formula self.comp = Composition(formula) def get_stoich(self): """ Returns dictionary of elements where the keys contains the stoichiometry e.g., LiPO4 returns {"Li" : 1, "P": 1, "O": 4} """ return self.comp.get_el_amt_dict() def uniq_elements(self): """ Returns list of unique elements e.g., LiPO4 returns ["Li","P","O"] """ return [*self.comp.get_el_amt_dict().keys()] def get_stoich_coeff(self,element): """ Returns stoichiometrric coefficient for element e.g., LiPO4 for element="O" would return 4 """ dict=self.get_stoich() return dict[element] def name(self): return self.formula
def get_band_center(form): c = Composition(str(form)) prod = 1.0 for el, amt in c.get_el_amt_dict().iteritems(): prod = prod * (Element(el).X ** amt) return -prod ** (1 / sum(c.get_el_amt_dict().values()))
def get_property(self, comp, property_name, combine_by_element=False): """ Args: x: (comp) Composition object (or str representation) property_name (str): combine_by_element (bool): Returns: (list): list of property values for the composition """ if property_name not in self.available_props: raise ValueError( "This descriptor is not available from the Magpie repository. " "Choose from {}".format(self.available_props)) if type(comp) == str: comp = Composition(comp) # Get data for given element/compound el_amt = comp.get_el_amt_dict() # sort symbols by electronegativity symbols = sorted(el_amt.keys(), key=lambda sym: get_el_sp(sym).Z) if combine_by_element: return [ self.all_elemental_props[property_name][el] for el in symbols ] else: return [ self.all_elemental_props[property_name][el] for el in symbols for _ in range(int(el_amt[el])) ]
def get_property(self, comp, property_name, combine_by_element=False): """ Args: x: (comp) Composition object (or str representation) property_name (str): see self.available_props for a list of possibilities combine_by_element (bool): If true, behavior will ignore stoichiometric ratios and will collapse all values for a single Element to one value (e.g., VO and VO2 will give the same data vector) Returns: (list): list of property values for the composition sorted by atomic number Z of each element """ if property_name not in self.available_props: raise ValueError( "This descriptor is not available from the Magpie repository. " "Choose from {}".format(self.available_props)) if type(comp) == str: comp = Composition(comp) # Get data for given element/compound el_amt = comp.get_el_amt_dict() # sort symbols by Z symbols = sorted(el_amt.keys(), key=lambda sym: get_el_sp(sym).Z) if combine_by_element: return [self.all_elemental_props[property_name][el] for el in symbols] else: return [self.all_elemental_props[property_name][el] for el in symbols for _ in range(int(el_amt[el]))]
def count_metals(d_i): comp = Composition(d_i['final_str'].formula.replace(" ", "")) comp_dict = comp.get_el_amt_dict() num_metals = 0.0 for i in comp_dict: for index, row in df_metals.iterrows(): if i == df_metals['Symbol'].iloc[index]: num_metals += comp_dict[i] return num_metals
def calc_formal_charge(self, comp): """ Computes formal charge of each element in a composition Args: comp (str or Composition object): composition Returns: dictionary of elements and formal charges """ if type(comp) == str: comp = Composition(comp) el_amt = comp.get_el_amt_dict() symbols = sorted( el_amt.keys(), key=lambda sym: get_el_sp(sym).Z) # Sort by atomic number stoich = [el_amt[el] for el in symbols] charge_states = [] for el in symbols: try: charge_states.append(self.all_props["charge_states"][el]) except: charge_states.append([float("NaN")]) charge_sets = itertools.product(*charge_states) possible_fml_charge = [] for charge in charge_sets: if np.dot(charge, stoich) == 0: possible_fml_charge.append(charge) if len(possible_fml_charge) == 0: fml_charge_dict = dict(zip(symbols, len(symbols) * [float("NaN")])) elif len(possible_fml_charge) == 1: fml_charge_dict = dict(zip(symbols, possible_fml_charge[0])) else: scores = [] # Score for correct sorting for charge_state in possible_fml_charge: el_charge_sort = [ sym for (charge, sym) in sorted(zip(charge_state, symbols)) ] # Elements sorted by charge scores.append( sum(el_charge_sort[i] == symbols[i]) for i in range(len(symbols)) ) # Score based on number of elements in correct position fml_charge_dict = dict( zip(symbols, possible_fml_charge[scores.index( max(scores))])) # Get charge states with best score return fml_charge_dict
def get_property(self, comp, property_name): comp = Composition(comp) if property_name not in self.available_props: raise ValueError("This descriptor is not available from the Magpie repository. " "Choose from {}".format(self.available_props)) # Get data for given element/compound el_amt = comp.get_el_amt_dict() # sort symbols by electronegativity symbols = sorted(el_amt.keys(), key=lambda sym: get_el_sp(sym).X) return [self.all_elemental_props[property_name][el] for el in symbols for _ in range(int(el_amt[el]))]
def _get_poly_formula(self, geometry: Dict[str, Any], nn_sites: List[Dict[str, Any]], nnn_sites: List[Dict[str, Any]]) -> Optional[str]: """Gets the polyhedra formula of the nearest neighbor atoms. The polyhedral formula is effectively the sorted nearest neighbor atoms in a reduced format. For example, if the nearest neighbors are 3 I atoms, 2 Br atoms and 1 Cl atom, the polyhedral formula will be "I3Br2Cl". The polyhedral formula will be ``None`` if the site geometry is not in :data:`robocrys.util.connected_geometries`. Args: geometry: The site geometry as produced by :meth:`SiteAnalyzer.get_site_geometry`. nn_sites: The nearest neighbor sites as produced by :meth:`SiteAnalyzer.get_nearest_neighbors`. nnn_sites: The next nearest neighbor sites as produced by :meth:`SiteAnalyzer.get_next_nearest_neighbors`. Returns: The polyhedral formula if the site geometry is in :data:`robocrys.util.connected_geometries` else ``None``. """ def order_elements(el): if self.use_iupac_formula: return [get_el_sp(el).X, el] else: return [get_el_sp(el).iupac_ordering, el] nnn_geometries = [nnn_site['geometry'] for nnn_site in nnn_sites] poly_formula = None if (geometry['type'] in connected_geometries and any([ nnn_geometry['type'] in connected_geometries for nnn_geometry in nnn_geometries ])): nn_els = [get_el(nn_site['element']) for nn_site in nn_sites] comp = Composition("".join(nn_els)) el_amt_dict = comp.get_el_amt_dict() poly_formula = "" for e in sorted(el_amt_dict.keys(), key=order_elements): poly_formula += e poly_formula += formula_double_format(el_amt_dict[e]) return poly_formula
def get_property(self, comp, property_name, combine_by_element=False): """ Args: x: (comp) Composition object (or str representation) property_name (str): combine_by_element (bool): Returns: (list): list of property values for the composition """ if property_name not in self.available_props: raise ValueError("This descriptor is not available") if type(comp) == str: comp = Composition(comp) # Get data for given element/compound el_amt = comp.get_el_amt_dict() # sort symbols by electronegativity symbols = sorted(el_amt.keys(), key=lambda sym: get_el_sp(sym).Z) demldata = [] if property_name == "formal_charge": fml_charge_dict = self.calc_formal_charge(comp) for el in symbols: try: prop = float(fml_charge_dict[el]) except: prop = float("NaN") if combine_by_element: demldata.append(prop) else: for _ in range(int(el_amt[el])): demldata.append(prop) elif property_name == "first_ioniz": # First ionization energy for el in symbols: try: first_ioniz = self.all_props["ionization_en"][el][0] except: first_ioniz = float("NaN") if combine_by_element: demldata.append(first_ioniz) else: for _ in range(int(el_amt[el])): demldata.append(first_ioniz) elif property_name == "total_ioniz": # Cumulative ionization energy for el in symbols: try: total_ioniz = sum(self.all_props["ionization_en"][el]) except: total_ioniz = float("NaN") if combine_by_element: demldata.append(total_ioniz) else: for _ in range(int(el_amt[el])): demldata.append(total_ioniz) elif "valence" in property_name: for el in symbols: valence_dict = self.all_props["valence_e"][ self.all_props["col_num"][el]] if property_name[-1] in ["s", "p", "d"]: if combine_by_element: demldata.append(float(valence_dict[property_name[-1]])) else: for _ in range(int(el_amt[el])): demldata.append( float(valence_dict[property_name[-1]])) else: n_valence = sum(valence_dict.values()) if combine_by_element: demldata.append(float(n_valence)) else: for _ in range(int(el_amt[el])): demldata.append(float(n_valence)) elif property_name in [ "xtal_field_split", "magn_moment", "so_coupling", "sat_magn" ]: # Charge dependent properties fml_charge_dict = self.calc_formal_charge(comp) for el in symbols: try: charge = fml_charge_dict[el] prop = float(self.all_props[property_name][el][charge]) except: prop = 0.0 if combine_by_element: demldata.append(prop) else: for _ in range(int(el_amt[el])): demldata.append(prop) return demldata else: for el in symbols: try: prop = float(self.all_props[property_name][el]) except: prop = float("NaN") if combine_by_element: demldata.append(prop) else: for _ in range(int(el_amt[el])): demldata.append(prop) return demldata