"""A calculator class for determining chemical potential distance of reactions."""from__future__importannotationsfromitertoolsimportchain,combinations,productfromtypingimportTYPE_CHECKING,Callableimportnumpyasnpfromrxn_network.costs.baseimportCalculatorfromrxn_network.thermo.chempot_diagramimportChemicalPotentialDiagramifTYPE_CHECKING:fromcollections.abcimportIterablefrompymatgen.analysis.phase_diagramimportPDEntryfromrxn_network.reactions.computedimportComputedReactionfromrxn_network.reactions.hullimportInterfaceReactionHull
[docs]classChempotDistanceCalculator(Calculator):"""Calculator for determining the aggregated "chemical potential distance" for a reaction, in units of eV/atom. This is a reaction selectivity metric based on an aggregation function applied to the chemical potential differences of reactant- product and product-product interfaces in a reaction. If you use this cost metric, please cite the following work: Todd, P. K.; McDermott, M. J.; Rom, C. L.; Corrao, A. A.; Denney, J. J.; Dwaraknath, S. S.; Khalifah, P. G.; Persson, K. A.; Neilson, J. R. Selectivity in Yttrium Manganese Oxide Synthesis via Local Chemical Potentials in Hyperdimensional Phase Space. J. Am. Chem. Soc. 2021, 143 (37), 15185-15194. https://doi.org/10.1021/jacs.1c06229. """def__init__(self,cpd:ChemicalPotentialDiagram,mu_func:Callable|str="sum",name:str="chempot_distance",):""" Args: cpd: the chemical potential diagram for the phase space in which the reaction(s) exist mu_func: the function (or string name of the function) used to aggregate the interfacial chemical potential distances into a single value describing the whole reaction. Current options are 1) max, 2) mean, and 3) sum (default). name: the data dictionary key with which to store the calculated value. Defaults to "chempot_distance". """self.cpd=cpdself.name=nameifmu_func=="max":self.mu_func=maxelifmu_func=="mean":self.mu_func=np.mean# type: ignoreelifmu_func=="sum":self.mu_func=sum# type: ignoreelifisinstance(mu_func,str):raiseValueError("Provided mu_func name is not a known function; please provide the function directly.")self._open_elems=set()ifcpd.entries[0].__class__.__name__=="GrandPotPDEntry":self._open_elems=set(cpd.entries[0].chempots.keys())
[docs]defcalculate(self,rxn:ComputedReaction)->float:"""Calculates the aggregate chemical potential distance in eV/atom. The mu_func parameter determines how the individual pairwise interface distances are aggregated into a single value describing the overall reaction. When mu_func = "sum" (i.e., the default setting), the total chemical potential distance is returned. Args: rxn: the ComputedReaction object Returns: The aggregate chemical potential distance of the reaction in eV/atom. """reactant_entries=rxn.reactant_entriesproduct_entries=rxn.product_entriesifhasattr(rxn,"grand_entries"):reactant_entries=[efore,cinzip(rxn.grand_entries,rxn.coefficients)ifc<0ande.__class__.__name__=="GrandPotPDEntry"]product_entries=[efore,cinzip(rxn.grand_entries,rxn.coefficients)ifc>0ande.__class__.__name__=="GrandPotPDEntry"]combos=chain(product(reactant_entries,product_entries),combinations(product_entries,2),)distances=[self.cpd.shortest_domain_distance(combo[0].composition.reduced_formula,combo[1].composition.reduced_formula,offset=self.cpd.get_offset(combo[0])+self.cpd.get_offset(combo[1]),)forcomboincombos]returnround(float(self.mu_func(distances)),5)
[docs]@classmethoddeffrom_entries(cls,entries:list[PDEntry],mu_func:Callable[[Iterable[float]],float]|str="sum",name:str="chempot_distance",**kwargs,)->ChempotDistanceCalculator:"""Convenience constructor which first builds the ChemicalPotentialDiagram object from a list of entry objects. Args: entries: entry objects used to build the ChemicalPotentialDiagram mu_func: the name of the function used to process the interfacial chemical potential distances into a single value describing the whole reaction. name: the data dictionary key by which to store the calculated value, defaults to "chempot_distance" **kwargs: optional kwargs passed to ChemicalPotentialDiagram. Returns: A ChempotDistanceCalculator object """cpd=ChemicalPotentialDiagram(entries=entries,**kwargs)returncls(cpd,mu_func,name)
[docs]classPrimaryCompetitionCalculator(Calculator):"""Calculator for determining the primary competition, C_1, for a reaction (units: eV/atom). If you use this selectivity metric in your work, please cite the following work: McDermott, M. J.; McBride, B. C.; Regier, C.; Tran, G. T.; Chen, Y.; Corrao, A. A.; Gallant, M. C.; Kamm, G. E.; Bartel, C. J.; Chapman, K. W.; Khalifah, P. G.; Ceder, G.; Neilson, J. R.; Persson, K. A. Assessing Thermodynamic Selectivity of Solid-State Reactions for the Predictive Synthesis of Inorganic Materials. arXiv August 22, 2023. https://doi.org/10.48550/arXiv.2308.11816. """def__init__(self,irh:InterfaceReactionHull,name:str="primary_competition",):""" Args: irh: the interface reaction hull containing the target reaction and all competing reactions. name: the data dictionary key with which to store the calculated value. Defaults to "primary_competition". """self.irh=irhself.name=name
[docs]defcalculate(self,rxn:ComputedReaction)->float:"""Calculates the competitiveness score for a given reaction by enumerating competing reactions, evaluating their cost with the supplied cost function, and then using the c-score formula, i.e. the _get_c_score() method, to determine the competitiveness score. Args: rxn: the ComputedReaction object to be evaluated Returns: The C1 score """returnself.irh.get_primary_competition(rxn)
[docs]classSecondaryCompetitionCalculator(Calculator):"""Calculator for determining the secondary competition, C_2, for a reaction (in eV/atom). If you use this selectivity metric in your work, please cite the following work: McDermott, M. J.; McBride, B. C.; Regier, C.; Tran, G. T.; Chen, Y.; Corrao, A. A.; Gallant, M. C.; Kamm, G. E.; Bartel, C. J.; Chapman, K. W.; Khalifah, P. G.; Ceder, G.; Neilson, J. R.; Persson, K. A. Assessing Thermodynamic Selectivity of Solid-State Reactions for the Predictive Synthesis of Inorganic Materials. arXiv August 22, 2023. https://doi.org/10.48550/arXiv.2308.11816. """def__init__(self,irh:InterfaceReactionHull,name:str="secondary_competition",):"""Args: irh: the interface reaction hull containing the target reaction and all competing reactions. name: the data dictionary key with which to store the calculated value. Defaults to "secondary_competition". """self.irh=irhself.name=name
[docs]defcalculate(self,rxn:ComputedReaction)->float:"""Calculates the secondary competition per its implementation in the InterfaceReactionHull class. Args: rxn: the ComputedReaction object to be evaluated Returns: The C2 score """returnself.irh.get_secondary_competition(rxn)
[docs]classSecondaryCompetitionWithEhullCalculator(Calculator):"""WARNING: this is an alternative calculator for secondary competition (C_2) that includes the energy above hull of the target reaciton. It should only be used for testing purposes. """def__init__(self,irh:InterfaceReactionHull,name:str="secondary_competition_with_ehull",):""" Args: irh: the interface reaction hull containing the target reaction and all competing reactions. name: the data dictionary key with which to store the calculated value. Defaults to "secondary_competition_with_ehull". """self.irh=irhself.name=name
[docs]defcalculate(self,rxn:ComputedReaction)->float:"""Calculates the secondary competition with e_hull per its implementation in the InterfaceReactionHull class. Args: rxn: the ComputedReaction object to be evaluated Returns: The C2 + e_hull score """returnself.irh.get_secondary_competition(rxn,include_e_hull=True)
[docs]classSecondaryCompetitionMaxCalculator(Calculator):"""WARNING: this is an alternative calculator for secondary competition (C_2) that defaults to calculation of the maximum secondary reaction energy. It should only be used for testing purposes. """def__init__(self,irh:InterfaceReactionHull,name:str="secondary_competition_max",):""" Args: irh: the interface reaction hull containing the target reaction and all competing reactions. name: the data dictionary key with which to store the calculated value. Defaults to "secondary_competition_max". """self.irh=irhself.name=name
[docs]defcalculate(self,rxn:ComputedReaction)->float:"""Calculates the secondary competition with max energies. Args: rxn: the ComputedReaction object to be evaluated Returns: The C2 score using max energies. """returnself.irh.get_secondary_competition_max_energy(rxn)
[docs]classSecondaryCompetitionAreaCalculator(Calculator):"""WARNING: this is an alternative calculator for secondary competition (C_2) that defaults to calculation of the area of the enclosed hull. It should only be used for testing purposes and is quite unstable. """def__init__(self,irh:InterfaceReactionHull,name:str="secondary_competition_area",):""" Args: irh: the interface reaction hull containing the target reaction and all competing reactions. name: the data dictionary key with which to store the calculated value. Defaults to "secondary_competition_area". """self.irh=irhself.name=name
[docs]defcalculate(self,rxn:ComputedReaction)->float:"""Calculates an area for secondary competition. Args: rxn: the ComputedReaction object to be evaluated Returns: Secondary competition as represented by area. """returnself.irh.get_secondary_competition_area(rxn)