コード例 #1
0
ファイル: test_composition.py プロジェクト: tongqcx/pymatgen
    def test_oxi_state_decoration(self):
        # Basic test: Get compositions where each element is in a single charge state
        decorated = Composition("H2O").add_charges_from_oxi_state_guesses()
        self.assertIn(Specie("H", 1), decorated)
        self.assertEqual(2, decorated.get(Specie("H", 1)))

        # Test: More than one charge state per element
        decorated = Composition("Fe3O4").add_charges_from_oxi_state_guesses()
        self.assertEqual(1, decorated.get(Specie("Fe", 2)))
        self.assertEqual(2, decorated.get(Specie("Fe", 3)))
        self.assertEqual(4, decorated.get(Specie("O", -2)))

        # Test: No possible charge states
        #   It should return an uncharged composition
        decorated = Composition("NiAl").add_charges_from_oxi_state_guesses()
        self.assertEqual(1, decorated.get(Specie("Ni", 0)))
        self.assertEqual(1, decorated.get(Specie("Al", 0)))
コード例 #2
0
    def test_oxi_state_decoration(self):
        # Basic test: Get compositions where each element is in a single charge state
        decorated = Composition("H2O").add_charges_from_oxi_state_guesses()
        self.assertIn(Specie("H", 1), decorated)
        self.assertEqual(2, decorated.get(Specie("H", 1)))

        # Test: More than one charge state per element
        decorated = Composition("Fe3O4").add_charges_from_oxi_state_guesses()
        self.assertEqual(1, decorated.get(Specie("Fe", 2)))
        self.assertEqual(2, decorated.get(Specie("Fe", 3)))
        self.assertEqual(4, decorated.get(Specie("O", -2)))

        # Test: No possible charge states
        #   It should return an uncharged composition
        decorated = Composition("NiAl").add_charges_from_oxi_state_guesses()
        self.assertEqual(1, decorated.get(Specie("Ni", 0)))
        self.assertEqual(1, decorated.get(Specie("Al", 0)))
コード例 #3
0
ファイル: ion.py プロジェクト: zacharygibbs/pymatgen
class Ion(MSONable):
    """
    Basic ion object. It is just a Composition object with an additional
    variable to store charge.
    The net charge can either be represented as Mn++, or Mn+2, or Mn[2+].
    Note the order of the sign and magnitude in each representation.
    """
    def __init__(self, composition, charge=0.0, properties=None):
        """
        Flexible Ion construction, similar to Composition.
        For more information, please see pymatgen.core.Composition
        """
        self._composition = Composition(composition)
        self._charge = charge
        self._properties = properties if properties else {}

    def __getattr__(self, a):
        if a in self._properties:
            return self._properties[a]
        try:
            return getattr(self._composition, a)
        except:
            raise AttributeError(a)

    @staticmethod
    def from_formula(formula):
        charge = 0.0
        f = formula
        m = re.search(r"\[([^\[\]]+)\]", f)
        if m:
            m_chg = re.search("([\.\d]*)([+-])", m.group(1))
            if m_chg:
                if m_chg.group(1) != "":
                    charge += float(m_chg.group(1)) * \
                        (float(m_chg.group(2) + "1"))
                else:
                    charge += float(m_chg.group(2) + "1")
            f = f.replace(m.group(), "", 1)
        m = re.search(r"\(aq\)", f)
        if m:
            f = f.replace(m.group(), "", 1)
        for m_chg in re.finditer("([+-])([\.\d]*)", f):
            sign = m_chg.group(1)
            sgn = float(str(sign + "1"))
            if m_chg.group(2).strip() != "":
                charge += float(m_chg.group(2)) * sgn
            else:
                charge += sgn
            f = f.replace(m_chg.group(), "", 1)
        composition = Composition(f)
        return Ion(composition, charge)

    @property
    def formula(self):
        """
        Returns a formula string, with elements sorted by electronegativity,
        e.g., Li4 Fe4 P4 O16.
        """
        formula = self._composition.formula
        chg_str = ""
        if self._charge > 0:
            chg_str = " +" + formula_double_format(self._charge, False)
        elif self._charge < 0:
            chg_str = " " + formula_double_format(self._charge, False)
        return formula + chg_str

    @property
    def anonymized_formula(self):
        """
        An anonymized formula. Appends charge to the end
        of anonymized composition
        """
        anon_formula = self._composition.anonymized_formula
        chg = self._charge
        chg_str = ""
        if chg > 0:
            chg_str += ("{}{}".format('+', str(int(chg))))
        elif chg < 0:
            chg_str += ("{}{}".format('-', str(int(np.abs(chg)))))
        return anon_formula + chg_str

    @property
    def reduced_formula(self):
        """
        Returns a reduced formula string with appended charge.
        """
        reduced_formula = self._composition.reduced_formula
        charge = self._charge / float(
            self._composition.get_reduced_composition_and_factor()[1])
        if charge > 0:
            if abs(charge) == 1:
                chg_str = "[+]"
            else:
                chg_str = "[" + formula_double_format(charge, False) + "+]"
        elif charge < 0:
            if abs(charge) == 1:
                chg_str = "[-]"
            else:
                chg_str = "[{}-]".format(
                    formula_double_format(abs(charge), False))
        else:
            chg_str = "(aq)"
        return reduced_formula + chg_str

    @property
    def alphabetical_formula(self):
        """
        Returns a reduced formula string with appended charge
        """
        alph_formula = self._composition.alphabetical_formula
        chg_str = ""
        if self._charge > 0:
            chg_str = " +" + formula_double_format(self._charge, False)
        elif self._charge < 0:
            chg_str = " " + formula_double_format(self._charge, False)
        return alph_formula + chg_str

    @property
    def charge(self):
        """
        Charge of the ion
        """
        return self._charge

    @property
    def composition(self):
        """
        Return composition object
        """
        return self._composition

    @property
    def to_dict(self):
        """
        Returns:
            dict with composition, as well as charge
        """
        d = self._composition.to_dict
        d['charge'] = self._charge
        return d

    @classmethod
    def from_dict(cls, d):
        """
        Generates an ion object from a dict created by to_dict.

        Args:
            d:
                {symbol: amount} dict.
        """
        #        composition = Composition.from_dict(d['composition'])
        charge = d['charge']
        composition = Composition({i: d[i] for i in d if i != 'charge'})
        return Ion(composition, charge)

    @property
    def to_reduced_dict(self):
        """
        Returns:
            dict with element symbol and reduced amount e.g.,
            {"Fe": 2.0, "O":3.0}.
        """
        reduced_formula = self._composition.reduced_formula
        c = Composition(reduced_formula)
        d = c.to_dict
        d['charge'] = self._charge
        return d

    def __eq__(self, other):
        if self.composition != other.composition:
            return False
        if self.charge != other.charge:
            return False
        return True

    def __ne__(self, other):
        return not self.__eq__(other)

    def __add__(self, other):
        """
        Addition of two ions.
        """
        new_composition = self.composition + other.composition
        new_charge = self.charge + other.charge
        return Ion(new_composition, new_charge)

    def __sub__(self, other):
        """
        Subtraction of two ions
        """
        new_composition = self.composition - other.composition
        new_charge = self.charge - other.charge
        return Ion(new_composition, new_charge)

    def __mul__(self, other):
        """
        Multiplication of an Ion with a factor
        """
        new_composition = self.composition * other
        new_charge = self.charge * other
        return Ion(new_composition, new_charge)

    def __hash__(self):
        #for now, just use the composition hash code.
        return self._composition.__hash__()

    def __len__(self):
        return len(self._composition)

    def __str__(self):
        return self.formula

    def __repr__(self):
        return "Ion: " + self.formula

    def __getitem__(self, el):
        return self._composition.get(el, 0)
コード例 #4
0
ファイル: ion.py プロジェクト: bocklund/pymatgen
class Ion(MSONable):
    """
    Basic ion object. It is just a Composition object with an additional
    variable to store charge.
    The net charge can either be represented as Mn++, or Mn+2, or Mn[2+].
    Note the order of the sign and magnitude in each representation.
    """
    def __init__(self, composition, charge=0.0, properties=None):
        """
        Flexible Ion construction, similar to Composition.
        For more information, please see pymatgen.core.Composition
        """
        self._composition = Composition(composition)
        self._charge = charge
        self._properties = properties if properties else {}

    def __getattr__(self, a):
        if a in self._properties:
            return self._properties[a]
        try:
            return getattr(self._composition, a)
        except:
            raise AttributeError(a)

    @staticmethod
    def from_formula(formula):
        charge = 0.0
        f = formula
        m = re.search(r"\[([^\[\]]+)\]", f)
        if m:
            m_chg = re.search(r"([\.\d]*)([+-])", m.group(1))
            if m_chg:
                if m_chg.group(1) != "":
                    charge += float(m_chg.group(1)) * \
                        (float(m_chg.group(2) + "1"))
                else:
                    charge += float(m_chg.group(2) + "1")
            f = f.replace(m.group(), "", 1)
        m = re.search(r"\(aq\)", f)
        if m:
            f = f.replace(m.group(), "", 1)
        for m_chg in re.finditer(r"([+-])([\.\d]*)", f):
            sign = m_chg.group(1)
            sgn = float(str(sign + "1"))
            if m_chg.group(2).strip() != "":
                charge += float(m_chg.group(2)) * sgn
            else:
                charge += sgn
            f = f.replace(m_chg.group(), "", 1)
        composition = Composition(f)
        return Ion(composition, charge)

    @property
    def formula(self):
        """
        Returns a formula string, with elements sorted by electronegativity,
        e.g., Li4 Fe4 P4 O16.
        """
        formula = self._composition.formula
        chg_str = ""
        if self._charge > 0:
            chg_str = " +" + formula_double_format(self._charge, False)
        elif self._charge < 0:
            chg_str = " " + formula_double_format(self._charge, False)
        return formula + chg_str

    @property
    def anonymized_formula(self):
        """
        An anonymized formula. Appends charge to the end
        of anonymized composition
        """
        anon_formula = self._composition.anonymized_formula
        chg = self._charge
        chg_str = ""
        if chg > 0:
            chg_str += ("{}{}".format('+', str(int(chg))))
        elif chg < 0:
            chg_str += ("{}{}".format('-', str(int(np.abs(chg)))))
        return anon_formula + chg_str

    @property
    def reduced_formula(self):
        """
        Returns a reduced formula string with appended charge.
        """
        reduced_formula = self._composition.reduced_formula
        charge = self._charge / float(self._composition.
                                      get_reduced_composition_and_factor()[1])
        if charge > 0:
            if abs(charge) == 1:
                chg_str = "[+]"
            else:
                chg_str = "[" + formula_double_format(charge, False) + "+]"
        elif charge < 0:
            if abs(charge) == 1:
                chg_str = "[-]"
            else:
                chg_str = "[{}-]".format(formula_double_format(abs(charge),
                                                               False))
        else:
            chg_str = "(aq)"
        return reduced_formula + chg_str

    @property
    def alphabetical_formula(self):
        """
        Returns a reduced formula string with appended charge
        """
        alph_formula = self._composition.alphabetical_formula
        chg_str = ""
        if self._charge > 0:
            chg_str = " +" + formula_double_format(self._charge, False)
        elif self._charge < 0:
            chg_str = " " + formula_double_format(self._charge, False)
        return alph_formula + chg_str

    @property
    def charge(self):
        """
        Charge of the ion
        """
        return self._charge

    @property
    def composition(self):
        """
        Return composition object
        """
        return self._composition

    def as_dict(self):
        """
        Returns:
            dict with composition, as well as charge
        """
        d = self._composition.as_dict()
        d['charge'] = self._charge
        return d

    @classmethod
    def from_dict(cls, d):
        """
        Generates an ion object from a dict created by as_dict().

        Args:
            d:
                {symbol: amount} dict.
        """
#        composition = Composition.from_dict(d['composition'])
        charge = d['charge']
        composition = Composition({i: d[i] for i in d if i != 'charge'})
        return Ion(composition, charge)

    @property
    def to_reduced_dict(self):
        """
        Returns:
            dict with element symbol and reduced amount e.g.,
            {"Fe": 2.0, "O":3.0}.
        """
        reduced_formula = self._composition.reduced_formula
        c = Composition(reduced_formula)
        d = c.as_dict()
        d['charge'] = self._charge
        return d

    def __eq__(self, other):
        if self.composition != other.composition:
            return False
        if self.charge != other.charge:
            return False
        return True

    def __ne__(self, other):
        return not self.__eq__(other)

    def __add__(self, other):
        """
        Addition of two ions.
        """
        new_composition = self.composition + other.composition
        new_charge = self.charge + other.charge
        return Ion(new_composition, new_charge)

    def __sub__(self, other):
        """
        Subtraction of two ions
        """
        new_composition = self.composition - other.composition
        new_charge = self.charge - other.charge
        return Ion(new_composition, new_charge)

    def __mul__(self, other):
        """
        Multiplication of an Ion with a factor
        """
        new_composition = self.composition * other
        new_charge = self.charge * other
        return Ion(new_composition, new_charge)

    def __hash__(self):
        #for now, just use the composition hash code.
        return self._composition.__hash__()

    def __len__(self):
        return len(self._composition)

    def __str__(self):
        return self.formula

    def __repr__(self):
        return "Ion: " + self.formula

    def __getitem__(self, el):
        return self._composition.get(el, 0)
コード例 #5
0
		def is_ABO3_struc(row):
			comp = Composition(row)
			if round(comp.get('O')%3)==0:	# get Oxygen fraction, this should be a multiple of 3 to have a final formula in the format of A(A')B(B')O3
				return True
			return False
コード例 #6
0
		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