[docs]
class Model:
"""
Models store bipartite metabolite-reaction relations.
:param biomolecule: metabolites M in the model
:param reactions: reactions R in the model
:param relations: relations M x R or R x M in the model
"""
# pylint: disable=R0902,R0903
def __init__(
# pylint: disable=R0913
self,
biomolecule: set[Metabolite],
tuples: (
set[tuple[Metabolite, Reaction] | tuple[Reaction, Metabolite]] | None
) = None,
relations: dict[str, set[MRT]] | None = None,
) -> None:
"""
Initialize a model from a set of metabolites, reactions, and
metabolite-reaction relations.
"""
self.biomolecule = biomolecule
self.relations = relations or {
"reactant": cast(Set[MRT], set()),
"product": cast(Set[MRT], set()),
}
if tuples is not None:
self._add_tuples(tuples)
logging.debug(
"Init %s {%s}", str(self), " ".join(sorted(str(r) for r in self.reactions))
)
self._log("Init")
@property
def reactions(self) -> set[Reaction]:
"""
The set of reactions defined by this model, extracted from the
reaction and product triples.
"""
e_reactant = [r for _, r, _ in self.relations["reactant"]]
e_product = [r for _, r, _ in self.relations["product"]]
return cast(Set[Reaction], {*e_reactant, *e_product})
[docs]
def remove_seed_reactions(self):
"""
Remove reactions with empty products or reactants, which otherwise would
implicitly create seeds. Some modeling tools generate these to represent
exchanges with the environment.
"""
for todo in self.reactions:
reac = {rel for rel in self.relations["reactant"] if rel[1] == todo}
prod = {rel for rel in self.relations["product"] if rel[1] == todo}
if not bool(reac) or not bool(prod):
logging.debug(
"Removing seed reaction (%d) -%s-> (%d)", len(reac), todo, len(prod)
)
self.relations["reactant"] -= reac
self.relations["product"] -= prod
self._log("Removed")
def _add_tuples(self, tuples):
"""
Add tuples to the relations, either reactant or product depending on which
member is a metabolite.
"""
self.relations["reactant"].update(
[(m, r, m.provenance) for m, r in tuples if isinstance(m, Metabolite)]
)
self.relations["product"].update(
[(m, r, m.provenance) for r, m in tuples if isinstance(m, Metabolite)]
)
def _log(self, prefix="Model"):
"""Log model contents."""
for role in ["product", "reactant"]:
for m, r, t in sorted(list(self.relations[role]), key=lambda mrt: mrt[1]):
logging.debug(
"%s relation %s %s (%s, %s, %s)",
prefix,
str(r.name),
role,
str(m.biomolecule),
str(r.name),
str(t),
)
[docs]
def __str__(self) -> str:
"""String representation of class Model."""
return f"Model<{hex(id(self))}>"