Source code for reactord.substance.symbolic

"""Parent class of Substance.

Class to redefine algebraic operators.
"""

from typing import Union

import numpy as np
from numpy.typing import NDArray

from sympy import Eq, Equality, Symbol, symbols


[docs]class Symbolic: """Parent class of Substance. Redefines algebraic operators. This class is created as a parent class of Substance and redefines the __add__, __mul__, __rmul__, __gt__ and __truediv__ methods to allow the construction of chemical equations from algebraic operations with Substance objects. Parameters ---------- names : Union[str, np.ndarray] Array that stores the name attribute of the substances that participates in a chemical equation. expression : Symbol, optional Full chemical expression as a SymPy symbol, by default None. chem_equality : Equality, optional Full chemical expression as a SymPy Equality, by default None. Raises ------ TypeError "Substance's name must be a string." """ def __init__( self, names: Union[str, NDArray], expression: Symbol = None, chem_equality: Equality = None, ) -> None: # ===================================================================== # Name storing: # ===================================================================== if isinstance(names, str): self._names = np.array([names]) elif isinstance(names, np.ndarray): self._names = names else: raise TypeError("Substance's name must be a string.") # ===================================================================== # Expression: # ===================================================================== if expression is None: self._expression = symbols(names) else: self._expression = expression # ===================================================================== # Chem equality: # ===================================================================== if chem_equality is None: self._chem_equality = None else: self._chem_equality = chem_equality def __rmul__(self, coeff: Union[int, float]) -> "Symbolic": """Redefine the reverse '*' operand. Redefines the reverse '*' operand to specify the stoichiometric of each substance. Parameters ---------- coeff : Union[int, float] Stoichiometric coefficient. Returns ------- Symbolic New Symbolic object with the respective stoichiometric coefficient. Raises ------ TypeError "'*' operand defined only for 'int' or 'float' types." """ if not isinstance(coeff, (int, float)): raise TypeError( "'*' operand defined only for 'int' or 'float' types." ) new_sym = Symbolic( names=self._names, expression=coeff * self._expression, ) return new_sym def __mul__(self, coeff: Union[int, float]) -> "Symbolic": """Redefine the '*' operand. Redefines the '*' operand to specify the stoichiometric of each substance. Parameters ---------- coeff : Union[int, float] Stoichiometric coefficient. Returns ------- Symbolic New Symbolic object with the respective stoichiometric coefficient. """ return self.__rmul__(coeff) def __truediv__(self, coeff: Union[int, float]) -> "Symbolic": """Redefine the '/' operand. Redefines the '/' operand to specify the stoichiometric of each substance. Parameters ---------- coeff : Union[int, float] Stoichiometric coefficient. Returns ------- Symbolic New Symbolic object with the respective stoichiometric coefficient. Raises ------ TypeError "'/' operand defined only for 'int' or 'float' types." """ if not isinstance(coeff, (int, float)): raise TypeError( "'/' operand defined only for 'int' or 'float' types." ) new_sym = Symbolic( names=self._names, expression=self._expression / coeff, ) return new_sym def __add__(self, other_sym: "Symbolic") -> "Symbolic": """Redefine the '+' operand. Add two Symbolic objects to build a chemical expression. Parameters ---------- other_sym : Symbolic Symbolic object to add. Returns ------- Symbolic New Symbolic object that contains the sum of the two Symbolics, and stores the names and individual symbols of the addends. Raises ------ TypeError "'+' defined only for Symbolic type." """ if not isinstance(other_sym, Symbolic): raise TypeError("'+' defined only for Symbolic type.") new_sym = Symbolic( names=np.unique(np.append(self._names, other_sym._names)), expression=self._expression + other_sym._expression, ) return new_sym def __gt__(self, other_sym: "Symbolic") -> "Symbolic": """Redefine the '>' operand. Construct a chemical expression. Parameters ---------- other_sym : Symbolic The right-hand side of the chemical expression. Returns ------- Symbolic New Symbolic object that contains the sum of the two Symbolics, and stores the names and individual symbols of the addends. Also creates the full chemical equation to print. Raises ------ TypeError "'>' defined only for Symbolic type." """ if not isinstance(other_sym, Symbolic): raise TypeError("'>' defined only for Symbolic type.") new_sym = Symbolic( names=np.append(self._names, other_sym._names), expression=-self._expression + other_sym._expression, chem_equality=Eq(self._expression, other_sym._expression), ) return new_sym