2424from pymatgen .util .string import Stringify , formula_double_format
2525
2626if TYPE_CHECKING :
27- from collections .abc import Generator , ItemsView , Iterator
27+ from collections .abc import Generator , ItemsView , Iterator , Mapping
2828 from typing import Any , ClassVar , Literal
2929
3030 from typing_extensions import Self
@@ -115,11 +115,11 @@ class Composition(collections.abc.Hashable, collections.abc.Mapping, MSONable, S
115115 # Tolerance in distinguishing different composition amounts.
116116 # 1e-8 is fairly tight, but should cut out most floating point arithmetic
117117 # errors.
118- amount_tolerance = 1e-8
119- charge_balanced_tolerance = 1e-8
118+ amount_tolerance : ClassVar [ float ] = 1e-8
119+ charge_balanced_tolerance : ClassVar [ float ] = 1e-8
120120
121121 # Special formula handling for peroxides and certain elements. This is so
122- # that formula output does not write LiO instead of Li2O2 for example.
122+ # that formula output does not write " LiO" instead of " Li2O2" for example.
123123 special_formulas : ClassVar [dict [str , str ]] = {
124124 "LiO" : "Li2O2" ,
125125 "NaO" : "Na2O2" ,
@@ -134,7 +134,8 @@ class Composition(collections.abc.Hashable, collections.abc.Mapping, MSONable, S
134134 "H" : "H2" ,
135135 }
136136
137- oxi_prob = None # prior probability of oxidation used by oxi_state_guesses
137+ # Prior probability of oxidation used by oxi_state_guesses
138+ oxi_prob : ClassVar [dict | None ] = None
138139
139140 def __init__ (self , * args , strict : bool = False , ** kwargs ) -> None :
140141 """Very flexible Composition construction, similar to the built-in Python
@@ -417,35 +418,38 @@ def get_reduced_composition_and_factor(self) -> tuple[Self, float]:
417418 """Calculate a reduced composition and factor.
418419
419420 Returns:
420- A normalized composition and a multiplicative factor, i.e. ,
421- Li4Fe4P4O16 returns (Composition("LiFePO4"), 4).
421+ tuple[Composition, float]: Normalized Composition and multiplicative factor,
422+ i.e. " Li4Fe4P4O16" returns (Composition("LiFePO4"), 4).
422423 """
423- factor = self .get_reduced_formula_and_factor ()[1 ]
424+ factor : float = self .get_reduced_formula_and_factor ()[1 ]
424425 return self / factor , factor
425426
426427 def get_reduced_formula_and_factor (self , iupac_ordering : bool = False ) -> tuple [str , float ]:
427428 """Calculate a reduced formula and factor.
428429
429430 Args:
430431 iupac_ordering (bool, optional): Whether to order the
431- formula by the iupac "electronegativity" series, defined in
432+ formula by the IUPAC "electronegativity" series, defined in
432433 Table VI of "Nomenclature of Inorganic Chemistry (IUPAC
433434 Recommendations 2005)". This ordering effectively follows
434- the groups and rows of the periodic table, except the
435+ the groups and rows of the periodic table, except for
435436 Lanthanides, Actinides and hydrogen. Note that polyanions
436437 will still be determined based on the true electronegativity of
437438 the elements.
438439
439440 Returns:
440- A pretty normalized formula and a multiplicative factor, i.e. ,
441- Li4Fe4P4O16 returns (LiFePO4, 4).
441+ tuple[str, float]: Normalized formula and multiplicative factor,
442+ i.e., " Li4Fe4P4O16" returns (LiFePO4, 4).
442443 """
443- all_int = all (abs (val - round (val )) < type (self ).amount_tolerance for val in self .values ())
444+ all_int : bool = all (abs (val - round (val )) < type (self ).amount_tolerance for val in self .values ())
444445 if not all_int :
445446 return self .formula .replace (" " , "" ), 1
446- el_amt_dict = {key : round (val ) for key , val in self .get_el_amt_dict ().items ()}
447+
448+ el_amt_dict : dict [str , int ] = {key : round (val ) for key , val in self .get_el_amt_dict ().items ()}
449+ factor : float
447450 formula , factor = reduce_formula (el_amt_dict , iupac_ordering = iupac_ordering )
448451
452+ # Do not "completely reduce" certain formulas
449453 if formula in type (self ).special_formulas :
450454 formula = type (self ).special_formulas [formula ]
451455 factor /= 2
@@ -458,10 +462,10 @@ def get_integer_formula_and_factor(
458462 """Calculate an integer formula and factor.
459463
460464 Args:
461- max_denominator (int): all amounts in the el:amt dict are
462- first converted to a Fraction with this maximum denominator
465+ max_denominator (int): all amounts in the el_amt dict are
466+ first converted to a Fraction with this maximum denominator.
463467 iupac_ordering (bool, optional): Whether to order the
464- formula by the iupac "electronegativity" series, defined in
468+ formula by the IUPAC "electronegativity" series, defined in
465469 Table VI of "Nomenclature of Inorganic Chemistry (IUPAC
466470 Recommendations 2005)". This ordering effectively follows
467471 the groups and rows of the periodic table, except the
@@ -470,13 +474,14 @@ def get_integer_formula_and_factor(
470474 the elements.
471475
472476 Returns:
473- A pretty normalized formula and a multiplicative factor, i.e.,
474- Li0.5O0.25 returns (Li2O, 0.25). O0.25 returns (O2, 0.125)
477+ A normalized formula and a multiplicative factor, i.e.,
478+ " Li0.5O0.25" returns (Li2O, 0.25). " O0.25" returns (O2, 0.125)
475479 """
476- el_amt = self .get_el_amt_dict ()
477- _gcd = gcd_float (list (el_amt .values ()), 1 / max_denominator )
480+ el_amt : dict [ str , float ] = self .get_el_amt_dict ()
481+ _gcd : float = gcd_float (list (el_amt .values ()), 1 / max_denominator )
478482
479- dct = {key : round (val / _gcd ) for key , val in el_amt .items ()}
483+ dct : dict [str , int ] = {key : round (val / _gcd ) for key , val in el_amt .items ()}
484+ factor : float
480485 formula , factor = reduce_formula (dct , iupac_ordering = iupac_ordering )
481486 if formula in type (self ).special_formulas :
482487 formula = type (self ).special_formulas [formula ]
@@ -485,8 +490,8 @@ def get_integer_formula_and_factor(
485490
486491 @property
487492 def reduced_formula (self ) -> str :
488- """A pretty normalized formula, i.e., LiFePO4 instead of
489- Li4Fe4P4O16.
493+ """A normalized formula, i.e., " LiFePO4" instead of
494+ " Li4Fe4P4O16" .
490495 """
491496 return self .get_reduced_formula_and_factor ()[0 ]
492497
@@ -1055,7 +1060,7 @@ def _get_oxi_state_guesses(
10551060 raise ValueError (f"Composition { comp } cannot accommodate max_sites setting!" )
10561061
10571062 # Load prior probabilities of oxidation states, used to rank solutions
1058- if not type (self ).oxi_prob :
1063+ if type (self ).oxi_prob is None :
10591064 all_data = loadfn (f"{ MODULE_DIR } /../analysis/icsd_bv.yaml" )
10601065 type(self ).oxi_prob = {Species .from_str (sp ): data for sp , data in all_data ["occurrence" ].items ()}
10611066 oxi_states_override = oxi_states_override or {}
@@ -1319,38 +1324,38 @@ def _parse_chomp_and_rank(match, formula: str, m_dict: dict[str, float], m_point
13191324
13201325
13211326def reduce_formula (
1322- sym_amt : dict [str , float ] | dict [ str , int ],
1327+ sym_amt : Mapping [str , float ],
13231328 iupac_ordering : bool = False ,
1324- ) -> tuple [str , float ]:
1325- """Helper function to reduce a sym_amt dict to a reduced formula and factor .
1329+ ) -> tuple [str , int ]:
1330+ """Helper function to reduce a symbol-amount mapping .
13261331
13271332 Args:
1328- sym_amt (dict): {symbol: amount} .
1333+ sym_amt (dict[str, float] ): Symbol to amount mapping .
13291334 iupac_ordering (bool, optional): Whether to order the
1330- formula by the iupac "electronegativity" series, defined in
1335+ formula by the IUPAC "electronegativity" series, defined in
13311336 Table VI of "Nomenclature of Inorganic Chemistry (IUPAC
13321337 Recommendations 2005)". This ordering effectively follows
1333- the groups and rows of the periodic table, except the
1338+ the groups and rows of the periodic table, except for
13341339 Lanthanides, Actinides and hydrogen. Note that polyanions
13351340 will still be determined based on the true electronegativity of
13361341 the elements.
13371342
13381343 Returns:
1339- tuple[str, float ]: reduced formula and factor.
1344+ tuple[str, int ]: reduced formula and factor.
13401345 """
1341- syms = sorted (sym_amt , key = lambda x : [get_el_sp (x ).X , x ])
1346+ syms : list [ str ] = sorted (sym_amt , key = lambda x : [get_el_sp (x ).X , x ])
13421347
13431348 syms = list (filter (lambda x : abs (sym_amt [x ]) > Composition .amount_tolerance , syms ))
13441349
1345- factor = 1
1346- # Enforce integers for doing gcd.
1350+ # Enforce integer for calculating greatest common divisor
1351+ factor : int = 1
13471352 if all (int (i ) == i for i in sym_amt .values ()):
13481353 factor = abs (gcd (* (int (i ) for i in sym_amt .values ())))
13491354
1350- poly_anions = []
1351- # if the composition contains a poly anion
1355+ # If the composition contains polyanion
1356+ poly_anions : list [ str ] = []
13521357 if len (syms ) >= 3 and get_el_sp (syms [- 1 ]).X - get_el_sp (syms [- 2 ]).X < 1.65 :
1353- poly_sym_amt = {syms [i ]: sym_amt [syms [i ]] / factor for i in [ - 2 , - 1 ] }
1358+ poly_sym_amt : dict [ str , float ] = {syms [i ]: sym_amt [syms [i ]] / factor for i in ( - 2 , - 1 ) }
13541359 poly_form , poly_factor = reduce_formula (poly_sym_amt , iupac_ordering = iupac_ordering )
13551360
13561361 if poly_factor != 1 :
@@ -1369,9 +1374,17 @@ def reduce_formula(
13691374 return "" .join ([* reduced_form , * poly_anions ]), factor
13701375
13711376
1377+ class CompositionError (Exception ):
1378+ """Composition exceptions."""
1379+
1380+
13721381class ChemicalPotential (dict , MSONable ):
1373- """Represent set of chemical potentials. Can be: multiplied/divided by a Number
1374- multiplied by a Composition (returns an energy) added/subtracted with other ChemicalPotentials.
1382+ """Represent set of chemical potentials.
1383+
1384+ Can be:
1385+ - multiplied/divided by a Number
1386+ - multiplied by a Composition (returns an energy)
1387+ - added/subtracted with other ChemicalPotentials
13751388 """
13761389
13771390 def __init__ (self , * args , ** kwargs ) -> None :
@@ -1424,7 +1437,3 @@ def get_energy(self, composition: Composition, strict: bool = True) -> float:
14241437 if strict and (missing := set (composition ) - set (self )):
14251438 raise ValueError (f"Potentials not specified for { missing } " )
14261439 return sum (self .get (key , 0 ) * val for key , val in composition .items ())
1427-
1428-
1429- class CompositionError (Exception ):
1430- """Exception class for composition errors."""
0 commit comments