Skip to content

Flux balance, flux variability, and parsimonious FBA

Flux balance analysis of a metabolic network, which sets its fluxes to maximise growth.

  • Name: flux_balance
  • Field: biology/systems_biology
  • Formalism: static solution
  • References: Raman 2021; Orth et al. 2010

Select this system

from skcomplex.systems import create_simulation, create_system, describe

system = create_system('flux_balance')
entry = describe('flux_balance')
trajectory = create_simulation('flux_balance').prepare().run().trajectory_

Factory

@register_system(
    field='biology/systems_biology',
    tags=('flux balance', 'linear program', 'metabolism', 'static'),
    references=('Raman 2021', 'Orth et al. 2010'),
    defaults={'until': 0.0},
)
def flux_balance(
    network: str = 'toy',
    *,
    oxygen: float = 1000.0,
    parsimonious: bool = False,
) -> System:
    """Return flux balance analysis of a metabolic network, which sets its fluxes to maximise growth.

    The steady-state balances of the metabolites and the bounds of the reactions confine the fluxes, and the optimum of
    the growth flux sets them (Raman 2021, Section 8.6). The toy network of Table 8.2 reaches growth 50, set by the
    bound 1000 on `v6`. The E. coli core system needs the extra `metabolism`, and grows at 0.8739 h^-1 on glucose with
    oxygen and at 0.2117 h^-1 without.

    Args:
        network:
            `'toy'` for Raman's toy network or `'ecoli'` for the E. coli core system.

        oxygen:
            The largest oxygen uptake of the E. coli core system.

        parsimonious:
            Whether to minimise the total absolute flux after growth.

    Returns:
        system:
            The system.

    Raises:
        ValidationError:
            The network is unknown.

        MissingExtraError:
            The E. coli core system needs the extra, which is not installed.

    Examples:
        >>> from skcomplex.core.engine.runtime import Simulation
        >>> from skcomplex.systems.biology.systems_biology import flux_balance
        >>> trajectory = Simulation(flux_balance()).prepare().run(0.0).trajectory_
        >>> round(float(trajectory.values('cell.v_vbio')[0]), 6)
        50.0
    """
    if network not in NETWORKS:
        error_msg = f'Unknown network {network!r}. Use one of {", ".join(NETWORKS)}.'
        raise ValidationError(error_msg)
    if network == 'toy':
        return System(elements=[ToyNetworkElement('cell', parsimonious=parsimonious)], time=StaticTime())
    element = load_network('textbook', 'cell', needed_by='flux_balance')
    element.parsimonious = parsimonious
    identifier = f'lower_{element._identifier(OXYGEN_EXCHANGE)}'
    element.set_params(**{identifier: -float(oxygen)})
    return System(elements=[element], time=StaticTime())

Components

Elements:

  • ToyNetworkElement, from DeclaredElement
class ToyNetworkElement(MetabolicNetworkElement):
    """The toy network of Table 8.2 of Raman (2021), which grows on A alone.

    Args:
        label:
            The label of the element.

        visual:
            How the element is drawn, or `None` for the bars of its program.

        objective:
            The coefficient of every reaction in the objective, or `None` for `default_objective`.

        parsimonious:
            Whether to minimise the total absolute flux after the objective.

        infeasible:
            The infeasibility policy of the program.

        name:
            The name of the network.

        reactions:
            The reactions by name.

        default_objective:
            The objective of the network when `objective` is `None`.

        variables:
            The declared states and parameters that replace the ones of the reactions, by name, or `None` for none.

    Examples:
        >>> from skcomplex.systems.biology.common.metabolism import ToyNetworkElement
        >>> ToyNetworkElement('cell').get_value('upper_v1')
        1000.0
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        objective: Mapping[str, float] | None = None,
        parsimonious: bool = False,
        infeasible: str = 'raise',
        name: str | None = 'ToyNetwork',
        reactions: Mapping[str, ReactionSpec] = TOY_REACTIONS,
        default_objective: Mapping[str, float] = TOY_OBJECTIVE,
        variables: Mapping[str, DeclaredVariableSpec] | None = None,
    ) -> None:
        super().__init__(
            label,
            visual,
            objective=objective,
            parsimonious=parsimonious,
            infeasible=infeasible,
            name=name,
            reactions=reactions,
            default_objective=default_objective,
            variables=variables,
        )