torchcell.metabolism.constraints.GemTensors

class GemTensors(*, s: Tensor, lb: Tensor, ub: Tensor, met_ids: list[str], rxn_ids: list[str], catalytic_units: CatalyticUnits, thermo: ThermoTable | None = None, independent_rows: Tensor | None = None, biomass_index: int | None = None, exchange_indices: Tensor | None = None, model_id: str = '', n_metabolites: int = 0, n_reactions: int = 0)[source]

Bases: BaseModel

A genome-scale model as tensors: stoichiometry, bounds, GPR, thermodynamics.

Everything is index-aligned: metabolite i is met_ids[i] in every tensor, reaction j is rxn_ids[j], gene g is catalytic_units.gene_ids[g].

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

property reversible_mask: Tensor

the reaction may run in either direction.

Type:

True where lb < 0 < ub

standard_reaction_delta_g() → tuple[Tensor, Tensor][source]

Recompute \(\Delta_r G'^\circ_j=\sum_i S_{ij}\Delta_f G'^\circ_i\).

The GEM ships a reaction table too, but it is recomputed from the metabolite table here for a reason worth stating: the reaction value is only meaningful when every participating metabolite carries a formation energy. Summing over a reaction with one unknown participant produces a number that looks like a free energy and is not one. The returned mask is therefore the AND over participants, which is strictly more conservative than trusting the shipped reaction column, and the two are compared in compare_reaction_delta_g().

Returns:

(delta_r_g0, mask) – both [r], energies in kJ/mol, zero where masked.