@@ -586,7 +586,8 @@ def contains_element_type(self, category: str) -> bool:
586586
587587 return any (getattr (el , f"is_{ category } " ) for el in self .elements )
588588
589- def _parse_formula (self , formula : str , strict : bool = True ) -> dict [str , float ]:
589+ @staticmethod
590+ def _parse_formula (formula : str , strict : bool = True ) -> dict [str , float ]:
590591 """
591592 Args:
592593 formula (str): A string formula, e.g. Fe2O3, Li3Fe2(PO4)3.
@@ -678,22 +679,64 @@ def from_dict(cls, dct: dict) -> Self:
678679 return cls (dct )
679680
680681 @classmethod
681- def from_weight_dict (cls , weight_dict : dict [SpeciesLike , float ]) -> Self :
682+ def from_weight_dict (cls , weight_dict : dict [SpeciesLike , float ], strict : bool = True , ** kwargs ) -> Self :
682683 """Create a Composition based on a dict of atomic fractions calculated
683684 from a dict of weight fractions. Allows for quick creation of the class
684685 from weight-based notations commonly used in the industry, such as
685686 Ti6V4Al and Ni60Ti40.
686687
687688 Args:
688689 weight_dict (dict): {symbol: weight_fraction} dict.
690+ strict (bool): Only allow valid Elements and Species in the Composition. Defaults to True.
691+ **kwargs: Additional kwargs supported by the dict() constructor.
689692
690693 Returns:
691- Composition
694+ Composition in molar fractions.
695+
696+ Examples:
697+ >>> Composition.from_weights({"Fe": 0.5, "Ni": 0.5})
698+ Composition('Fe0.512434 Ni0.487566')
699+ >>> Composition.from_weights({"Ti": 60, "Ni": 40})
700+ Composition('Ti0.647796 Ni0.352204')
692701 """
693702 weight_sum = sum (val / Element (el ).atomic_mass for el , val in weight_dict .items ())
694703 comp_dict = {el : val / Element (el ).atomic_mass / weight_sum for el , val in weight_dict .items ()}
695704
696- return cls (comp_dict )
705+ return cls (comp_dict , strict = strict , ** kwargs )
706+
707+ @classmethod
708+ def from_weights (cls , * args , strict : bool = True , ** kwargs ) -> Self :
709+ """Create a Composition from a weight-based formula.
710+
711+ Args:
712+ *args: Any number of 2-tuples as key-value pairs.
713+ strict (bool): Only allow valid Elements and Species in the Composition. Defaults to False.
714+ allow_negative (bool): Whether to allow negative compositions. Defaults to False.
715+ **kwargs: Additional kwargs supported by the dict() constructor.
716+
717+ Returns:
718+ Composition in molar fractions.
719+
720+ Examples:
721+ >>> Composition.from_weights("Fe50Ti50")
722+ Composition('Fe0.461538 Ti0.538462')
723+ >>> Composition.from_weights({"Fe": 0.5, "Ni": 0.5})
724+ Composition('Fe0.512434 Ni0.487566')
725+ """
726+ if len (args ) == 1 and isinstance (args [0 ], str ):
727+ elem_map : dict [str , float ] = cls ._parse_formula (args [0 ])
728+ elif len (args ) == 1 and isinstance (args [0 ], type (cls )):
729+ elem_map = args [0 ] # type: ignore[assignment]
730+ elif len (args ) == 1 and isinstance (args [0 ], float ) and math .isnan (args [0 ]):
731+ raise ValueError ("float('NaN') is not a valid Composition, did you mean 'NaN'?" )
732+ else :
733+ elem_map = dict (* args , ** kwargs ) # type: ignore[assignment]
734+
735+ for val in elem_map .values ():
736+ if val < - cls .amount_tolerance :
737+ raise ValueError ("Weights in Composition cannot be negative!" )
738+
739+ return cls .from_weight_dict (elem_map , strict = strict )
697740
698741 def get_el_amt_dict (self ) -> dict [str , float ]:
699742 """
0 commit comments