Source code for sbmlmath.csymbol
"""Handling of <csymbol> constants"""
from __future__ import annotations
import sympy as sp
__all__ = ["CSymbol", "TimeSymbol", "avogadro"]
#: The `Avogadro constant <https://en.wikipedia.org/wiki/Avogadro_constant>`_
# as defined in SBML L3V2 section 3.4.6.
SBML_L3V2_AVOGADRO_VALUE = 6.02214179e23
[docs]
class CSymbol(sp.Dummy):
"""
Represents a ``<csymbol>`` element.
Represents, for example the Avogadro constant, which is defined in SBML as:
.. code-block:: xml
<csymbol encoding="text" definitionURL="http://www.sbml.org/sbml/symbols/avogadro"> avogadro </csymbol>
and can be generated by:
>>> CSymbol("avogadro", definition_url="http://www.sbml.org/sbml/symbols/avogadro")
<avogadro(http://www.sbml.org/sbml/symbols/avogadro)>
>>> float(CSymbol("avogadro", definition_url="http://www.sbml.org/sbml/symbols/avogadro"))
6.02214179e+23
See also https://www.w3.org/TR/MathML2/chapter4.html#contm.csymbol.
"""
DEFINITION_URL = None
_cache = {}
_definition_url_to_derived_class = {}
def __new__(
cls,
*args,
definition_url: str,
encoding: str = "text",
**kwargs,
):
# Cache instances.
# If not done: (CSymbol("A") == CSymbol("A")) == False
if not (name := kwargs.get("name")):
name = args[0]
cache_key = (name, definition_url, encoding)
if cached := cls._cache.get(cache_key):
return cached
# return the matching subtype, depending on the definition URL
obj = super().__new__(
cls._definition_url_to_derived_class.get(definition_url, cls),
*args,
**kwargs,
)
# ensure there are no collisions with super() attributes
assert not hasattr(obj, "definition_url")
assert not hasattr(obj, "encoding")
obj.definition_url = definition_url
obj.encoding = encoding
cls._cache[cache_key] = obj
return obj
def __repr__(self):
return f"<{self.name}({self.definition_url})>"
def __eq__(self, other):
if not isinstance(other, CSymbol):
return False
# if they represent the same value, they are equal
return self.definition_url == other.definition_url
def __hash__(self):
# if we define __eq__, we also need __hash__ to use instances in sympy
# expressions
return hash(self.definition_url)
def __float__(self):
if self.definition_url == "http://www.sbml.org/sbml/symbols/avogadro":
return SBML_L3V2_AVOGADRO_VALUE
return super().__float__()
def _eval_evalf(self, prec):
if self.definition_url == "http://www.sbml.org/sbml/symbols/avogadro":
return sp.Float(SBML_L3V2_AVOGADRO_VALUE)
return super()._eval_evalf()
@classmethod
def register_subclass(cls, derived_class: type[CSymbol]):
cls._definition_url_to_derived_class[derived_class.DEFINITION_URL] = (
derived_class
)
#: SBML's `Avogadro constant <https://en.wikipedia.org/wiki/Avogadro_constant>`_
avogadro = CSymbol(
"avogadro", definition_url="http://www.sbml.org/sbml/symbols/avogadro"
)
[docs]
class TimeSymbol(CSymbol):
"""The current internal simulation time.
This symbol represents the current simulation time inside the model.
>>> TimeSymbol("t")
<t(http://www.sbml.org/sbml/symbols/time)>
Args:
name: The name of the symbol.
"""
DEFINITION_URL = "http://www.sbml.org/sbml/symbols/time"
def __new__(
cls,
name: str,
):
return super().__new__(
cls,
name=name,
definition_url=cls.DEFINITION_URL,
)
CSymbol.register_subclass(TimeSymbol)