def transform_entries(self, entries, terminal_compositions): """ Method to transform all entries to the composition coordinate in the terminal compositions. If the entry does not fall within the space defined by the terminal compositions, they are excluded. For example, Li3PO4 is mapped into a Li2O:1.5, P2O5:0.5 composition. The terminal compositions are represented by DummySpecies. Args: entries: Sequence of all input entries terminal_compositions: Terminal compositions of phase space. Returns: Sequence of TransformedPDEntries falling within the phase space. """ new_entries = [] if self.normalize_terminals: fractional_comp = [ c.get_fractional_composition() for c in terminal_compositions ] else: fractional_comp = terminal_compositions #Map terminal compositions to unique dummy species. sp_mapping = collections.OrderedDict() for i, comp in enumerate(fractional_comp): sp_mapping[comp] = DummySpecie("X" + chr(102 + i)) for entry in entries: try: rxn = Reaction(fractional_comp, [entry.composition]) rxn.normalize_to(entry.composition) #We only allow reactions that have positive amounts of #reactants. if all([ rxn.get_coeff(comp) <= CompoundPhaseDiagram.amount_tol for comp in fractional_comp ]): newcomp = { sp_mapping[comp]: -rxn.get_coeff(comp) for comp in fractional_comp } newcomp = { k: v for k, v in newcomp.items() if v > CompoundPhaseDiagram.amount_tol } transformed_entry = \ TransformedPDEntry(Composition(newcomp), entry) new_entries.append(transformed_entry) except ReactionError: #If the reaction can't be balanced, the entry does not fall #into the phase space. We ignore them. pass return new_entries, sp_mapping
def transform_entries(self, entries, terminal_compositions): """ Method to transform all entries to the composition coordinate in the terminal compositions. If the entry does not fall within the space defined by the terminal compositions, they are excluded. For example, Li3PO4 is mapped into a Li2O:1.5, P2O5:0.5 composition. The terminal compositions are represented by DummySpecies. Args: entries: Sequence of all input entries terminal_compositions: Terminal compositions of phase space. Returns: Sequence of TransformedPDEntries falling within the phase space. """ new_entries = [] if self.normalize_terminals: fractional_comp = [c.get_fractional_composition() for c in terminal_compositions] else: fractional_comp = terminal_compositions #Map terminal compositions to unique dummy species. sp_mapping = collections.OrderedDict() for i, comp in enumerate(fractional_comp): sp_mapping[comp] = DummySpecie("X" + chr(102 + i)) for entry in entries: try: rxn = Reaction(fractional_comp, [entry.composition]) rxn.normalize_to(entry.composition) #We only allow reactions that have positive amounts of #reactants. if all([rxn.get_coeff(comp) <= CompoundPhaseDiagram.amount_tol for comp in fractional_comp]): newcomp = {sp_mapping[comp]: -rxn.get_coeff(comp) for comp in fractional_comp} newcomp = {k: v for k, v in newcomp.items() if v > CompoundPhaseDiagram.amount_tol} transformed_entry = \ TransformedPDEntry(Composition(newcomp), entry) new_entries.append(transformed_entry) except ReactionError: #If the reaction can't be balanced, the entry does not fall #into the phase space. We ignore them. pass return new_entries, sp_mapping
def process_multientry(entry_list, prod_comp): """ Static method for finding a multientry based on a list of entries and a product composition. Essentially checks to see if a valid aqueous reaction exists between the entries and the product composition and returns a MultiEntry with weights according to the coefficients if so. Args: entry_list ([Entry]): list of entries from which to create a MultiEntry comp (Composition): composition constraint for setting weights of MultiEntry """ dummy_oh = [Composition("H"), Composition("O")] try: # Get balanced reaction coeffs, ensuring all < 0 or conc thresh # Note that we get reduced compositions for solids and non-reduced # compositions for ions because ions aren't normalized due to # their charge state. entry_comps = [e.composition if e.phase_type=='Ion' else e.composition.reduced_composition for e in entry_list] rxn = Reaction(entry_comps + dummy_oh, [prod_comp]) thresh = np.array([pe.conc if pe.phase_type == "Ion" else 1e-3 for pe in entry_list]) coeffs = -np.array([rxn.get_coeff(comp) for comp in entry_comps]) if (coeffs > thresh).all(): weights = coeffs / coeffs[0] return MultiEntry(entry_list, weights=weights.tolist()) else: return None except ReactionError: return None
def process_multientry(entry_list, prod_comp): """ Static method for finding a multientry based on a list of entries and a product composition. Essentially checks to see if a valid aqueous reaction exists between the entries and the product composition and returns a MultiEntry with weights according to the coefficients if so. Args: entry_list ([Entry]): list of entries from which to create a MultiEntry comp (Composition): composition constraint for setting weights of MultiEntry """ dummy_oh = [Composition("H"), Composition("O")] try: # Get balanced reaction coeffs, ensuring all < 0 or conc thresh # Note that we get reduced compositions for solids and non-reduced # compositions for ions because ions aren't normalized due to # their charge state. entry_comps = [e.composition if e.phase_type=='Ion' else e.composition.reduced_composition for e in entry_list] rxn = Reaction(entry_comps + dummy_oh, [prod_comp]) thresh = np.array([pe.conc if pe.phase_type == "Ion" else 1e-3 for pe in entry_list]) coeffs = -np.array([rxn.get_coeff(comp) for comp in entry_comps]) if (coeffs > thresh).all(): weights = coeffs / coeffs[0] return MultiEntry(entry_list, weights=weights.tolist()) else: return None except ReactionError: return None
def process_multientry(entry_list, prod_comp, coeff_threshold=1e-4): """ Static method for finding a multientry based on a list of entries and a product composition. Essentially checks to see if a valid aqueous reaction exists between the entries and the product composition and returns a MultiEntry with weights according to the coefficients if so. Args: entry_list ([Entry]): list of entries from which to create a MultiEntry prod_comp (Composition): composition constraint for setting weights of MultiEntry coeff_threshold (float): threshold of stoichiometric coefficients to filter, if weights are lower than this value, the entry is not returned """ dummy_oh = [Composition("H"), Composition("O")] try: # Get balanced reaction coeffs, ensuring all < 0 or conc thresh # Note that we get reduced compositions for solids and non-reduced # compositions for ions because ions aren't normalized due to # their charge state. entry_comps = [e.composition for e in entry_list] rxn = Reaction(entry_comps + dummy_oh, [prod_comp]) coeffs = -np.array([rxn.get_coeff(comp) for comp in entry_comps]) # Return None if reaction coeff threshold is not met # TODO: this filtration step might be put somewhere else if (coeffs > coeff_threshold).all(): return MultiEntry(entry_list, weights=coeffs.tolist()) else: return None except ReactionError: return None
def process_multientry(entry_list, prod_comp, coeff_threshold=1e-4): """ Static method for finding a multientry based on a list of entries and a product composition. Essentially checks to see if a valid aqueous reaction exists between the entries and the product composition and returns a MultiEntry with weights according to the coefficients if so. Args: entry_list ([Entry]): list of entries from which to create a MultiEntry prod_comp (Composition): composition constraint for setting weights of MultiEntry coeff_threshold (float): threshold of stoichiometric coefficients to filter, if weights are lower than this value, the entry is not returned """ dummy_oh = [Composition("H"), Composition("O")] try: # Get balanced reaction coeffs, ensuring all < 0 or conc thresh # Note that we get reduced compositions for solids and non-reduced # compositions for ions because ions aren't normalized due to # their charge state. entry_comps = [e.composition for e in entry_list] rxn = Reaction(entry_comps + dummy_oh, [prod_comp]) react_coeffs = [-rxn.get_coeff(comp) for comp in entry_comps] all_coeffs = react_coeffs + [rxn.get_coeff(prod_comp)] # Check if reaction coeff threshold met for pourbaix compounds # All reactant/product coefficients must be positive nonzero if all([coeff > coeff_threshold for coeff in all_coeffs]): return MultiEntry(entry_list, weights=react_coeffs) return None except ReactionError: return None