import cobra
import copy
from commmodelpy.commmodelpy import Community, SingleModel, generate_community_model_with_no_growth
from commmodelpy.submodules.helper_general import json_write
from typing import Dict

S = cobra.Metabolite(id="S_c", compartment="c")
A = cobra.Metabolite(id="A_c", compartment="c")
B = cobra.Metabolite(id="B_c", compartment="c")
C = cobra.Metabolite(id="C_c", compartment="c")
P = cobra.Metabolite(id="P_c", compartment="c")
X = cobra.Metabolite(id="X_c", compartment="c")

nil_to_S = cobra.Reaction(id="EX_A", lower_bound=0, upper_bound=1000)
S_to_A = cobra.Reaction(id="S_to_A", lower_bound=0, upper_bound=float("inf"))
A_to_B = cobra.Reaction(id="A_to_B", lower_bound=0, upper_bound=float("inf"))
B_to_C = cobra.Reaction(id="B_to_C", lower_bound=0, upper_bound=float("inf"))
C_to_P = cobra.Reaction(id="C_to_P", lower_bound=0, upper_bound=float("inf"))
P__to_nil = cobra.Reaction(id="EX_P", lower_bound=0, upper_bound=float("inf"))

nil_to_S.add_metabolites({S: 1})
S_to_A.add_metabolites({
    S: -1,
    A: 1,
    X: 1,
})
A_to_B.add_metabolites({
    A: -1,
    B: 1,
    X: -1,
})
Example #2
0
def sum_within_deviation(base):
    """Metabolites for a superficial, simple toy biomass reaction. The
    composition will follow the distribution depicted here:

    Lipid = 10% = 0.1 g/g
    Protein = 70% = 0.7 g/g
    RNA = 5% = 0.05 g/g
    DNA = 3% = 0.03 g/g
    Ash = 7% = 0.07 g/g
    Carbohydrates = 5% = 0.05 g/g

    The arbitrary molar masses for the metabolites used in this toy
    reaction will be approximated using hydrogen atoms in the formula.
    """
    met_a = cobra.Metabolite("lipid_c", "H744", compartment='c')
    met_b = cobra.Metabolite("protein_c", "H119", compartment='c')
    met_c = cobra.Metabolite("rna_c", "H496", compartment='c')
    met_d = cobra.Metabolite("dna_c", "H483", compartment='c')
    met_e = cobra.Metabolite("ash_c", "H80", compartment='c')
    met_f = cobra.Metabolite("cellwall_c", "H177", compartment='c')
    met_g = cobra.Metabolite("atp_c", "C10H12N5O13P3", compartment='c')
    met_h = cobra.Metabolite("adp_c", "C10H12N5O10P2", compartment='c')
    met_i = cobra.Metabolite("h_c", "H", compartment='c')
    met_j = cobra.Metabolite("h2o_c", "H2O", compartment='c')
    met_k = cobra.Metabolite("pi_c", "HO4P", compartment='c')
    # Reactions
    rxn_1 = cobra.Reaction("BIOMASS_TEST")
    rxn_1.add_metabolites({met_a: -0.133, met_b: -5.834, met_c: -0.1,
                           met_d: -0.0625, met_e: -0.875, met_f: -0.2778,
                           met_g: -30.0, met_h: 30.0, met_i: 30.0,
                           met_j: -30.0, met_k: 30.0
                           })
    base.add_reactions([rxn_1])
    return base
Example #3
0
def generate_community_model_with_no_growth(
        community: Community,
        fractions: Dict[str, float],
        biomass_reactions: Dict[str, str] = {}) -> cobra.Model:
    """Creates a cobrapy-compatible community model from a commmodelpy Community instance.

    Description
    ----------
    This function uses all information that is given to the Community
    instance's member variables - and its SingleModel member variables - in order
    to generate a community model with an exchange compartment, species-specific
    exchange reactions as well as community-wide exchange reactions as defined
    by the input and output metabolites of the respective Community instance
    and its SingleSpecies instances.

    Herein, the model-specific fractions of all single organisms can be given and for every species-associated
    function with a minimal/maximal flux which is not equal to inf/-inf/0, the
    minimal/maximal flux (denoted as v) is set to v*fraction_of_the_reaction's_species.
    Since only the growth rate is now free, this linearizes the 'problem' of solving
    a balanced-growth community model for growth, and an FBA on this model will show
    the theoretical optimal growth with the given fixed organism fractions.

    Return value
    ----------
    A community model with fixed species ratios and no growth in the form of a cobrapy
    Model instance. This form of the community model - with its fixed organism
    ratios - can be e.g. used with the ASTHERISC package.

    Arguments
    ----------
    * community: Community ~ The Community instance describing the total community. *In order to run with the ASTHERISC package,
      the community's exchange compartment ID must be set to "exchg" and the community's exchange reaction ID prefix to "EX_C"*.
    * fractions: Dict[str, float]: float ~ A dictionary containing all species names of
      the community as keys, and their fractions of the total community biomass as
      values. For reasonable calculations, the sum of all fractions should be 1.0.
    * biomass_reactions: Dict[str, str] ~ If not {}, it must denote the biomass reaction IDs (values) for each
      of the community's species (keys). For these reactions, the mock biomass metabolite community_biomass_$SPECIES_NAME
      will be added as product and the objective function community_biomass_reaction will be able to consume it.
      If it is {}, no objective function will be created and the mock biomass metabolites will not be added to the species biomass reaction.
      Is {} by default.
    """
    # Get number of SingleModel instances in Community instance
    num_single_models = len(community.single_models)
    # Check that an actual community is given
    if num_single_models <= 1:
        raise ValueError(
            "ERROR: Less than 2 models in given Community instance!")
    # Check that the right amount of fractions is given
    if len(fractions.keys()) != num_single_models:
        raise ValueError(
            f"ERROR: Number of given fractions ({len(fractions)}) does not match number of single models ({num_single_models})!"
        )

    # Go through each SingleModel and change their cobra models
    for single_model in community.single_models:
        species_fraction = fractions[single_model.species_abbreviation]

        # Check that no underscores are in the organism IDs
        if "_" in single_model.species_abbreviation:
            raise ValueError(
                f"ERROR: Underscore in the given species abbreviation {single_model.species_abbreviation} D:"
            )

        # Rename metabolites
        for metabolite in single_model.cobra_model.metabolites:
            metabolite.id += "_" + single_model.species_abbreviation

        # Rename reactions and change bounds
        for reaction in single_model.cobra_model.reactions:
            reaction.id += "_" + single_model.species_abbreviation

            if reaction.upper_bound != float("inf"):
                reaction.upper_bound *= species_fraction
            if reaction.lower_bound != -float("inf"):
                reaction.lower_bound *= species_fraction
            if (reaction.upper_bound == float("inf")) and (species_fraction
                                                           == 0):
                reaction.upper_bound = 0
            if (reaction.lower_bound == -float("inf")) and (species_fraction
                                                            == 0):
                reaction.lower_bound = 0

        # Delete standard exchange reactions with default exchange reaction ID prefix
        standard_exchanges = [
            x for x in single_model.cobra_model.reactions
            if x.id.startswith(single_model.exchange_reaction_id_prefix)
        ]
        single_model.cobra_model.remove_reactions(standard_exchanges)

    # Merge single models into a huge one
    merged_model = copy.deepcopy(community.single_models[0].cobra_model)
    for single_model in community.single_models[1:]:
        merged_model.merge(single_model.cobra_model, inplace=True)

    # Add whole community exchanges
    exchange_metabolite_ids = list(
        set(community.input_metabolite_ids + community.output_metabolite_ids))
    for exchange_metabolite_id in exchange_metabolite_ids:
        # Set reaction instance
        reaction = cobra.Reaction(
            id=community.exchange_reaction_id_prefix + exchange_metabolite_id +
            "_" + community.exchange_compartment_id,
            name="Community exchange for " + exchange_metabolite_id)

        # Set reaction bounds
        is_input = exchange_metabolite_id in community.input_metabolite_ids
        if is_input:
            reaction.lower_bound = -float("inf")
        else:
            reaction.lower_bound = 0
        is_output = exchange_metabolite_id in community.output_metabolite_ids
        if is_output:
            reaction.upper_bound = float("inf")
        else:
            reaction.upper_bound = 0

        # Add metabolite to reaction
        exchange_metabolite = cobra.Metabolite(
            exchange_metabolite_id + "_" + community.exchange_compartment_id,
            name="Exchange compartment metabolite " + exchange_metabolite_id,
            compartment="exchange")
        reaction.add_metabolites({
            exchange_metabolite: -1,
        })

        # Add reaction to model
        merged_model.add_reactions([reaction])

    # Add mock community biomass metabolites for the ASTHERISC package's species recognition
    biomass_metabolite = cobra.Metabolite(
        id="community_biomass",
        name=
        "Mock community biomass metabolite for ASTHERISC package species recognition",
        compartment="exchg")
    merged_model.add_metabolites([biomass_metabolite])

    # Add single species <-> exchange compartment exchanges
    for single_model in community.single_models:
        exchange_metabolite_ids = list(
            set(single_model.input_metabolite_ids +
                single_model.output_metabolite_ids))
        exchange_metabolite_ids = [
            x + "_" + single_model.species_abbreviation
            for x in exchange_metabolite_ids
        ]

        # Add mock community biomass metabolites for the ASTHERISC package's species recognition
        biomass_metabolite = cobra.Metabolite(
            id="community_biomass_" + single_model.species_abbreviation,
            name=
            "Mock community biomass metabolite for ASTHERISC package species recognition",
            compartment="exchg")
        merged_model.add_metabolites([biomass_metabolite])

        for exchange_metabolite_id in exchange_metabolite_ids:
            exchange_compartment_metabolite_id = single_model.model_metabolite_to_exchange_id_mapping[
                exchange_metabolite_id.replace(
                    "_" + single_model.species_abbreviation, "")]

            # Set reaction instance
            reaction = cobra.Reaction(
                id="EXCHG_" + single_model.species_abbreviation + "_" +
                exchange_metabolite_id.replace(
                    "_" + single_model.species_abbreviation, "") + "_to_" +
                exchange_compartment_metabolite_id,
                name=
                f"Exchange for {exchange_metabolite_id} from single species {single_model.species_abbreviation} to exchange compartment"
            )

            # Set reaction bounds
            # is_input = exchange_compartment_metabolite_id in single_model.input_metabolite_ids
            is_input = exchange_metabolite_id.replace(
                "_" + single_model.species_abbreviation,
                "") in single_model.input_metabolite_ids
            if is_input:
                reaction.lower_bound = -float("inf")
            else:
                reaction.lower_bound = 0
            # is_output = exchange_compartment_metabolite_id in single_model.output_metabolite_ids
            is_output = exchange_metabolite_id.replace(
                "_" + single_model.species_abbreviation,
                "") in single_model.output_metabolite_ids
            if is_output:
                reaction.upper_bound = float("inf")
            else:
                reaction.upper_bound = 0

            # Add metabolites to reaction
            internal_metabolite = merged_model.metabolites.get_by_id(
                exchange_metabolite_id)
            exchange_compartment_metabolite = merged_model.metabolites.get_by_id(
                exchange_compartment_metabolite_id + "_" +
                community.exchange_compartment_id)
            reaction.add_metabolites({
                internal_metabolite: -1,
                exchange_compartment_metabolite: 1,
            })

            # Add reaction to model
            merged_model.add_reactions([reaction])

    return merged_model
Example #4
0
    1339, 1340, 1353, 1370, 1371, 1373, 1374, 1376, 1384, 1387, 1406, 1408,
    1410, 1433, 1445, 1448, 1449, 1457, 1480, 1481, 1486, 1510, 1517, 1518,
    1537, 1538, 1539, 1541, 1548, 1549, 1583, 1585, 1596, 1600, 1633, 1640,
    1645, 1647, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692
]

# cobra.io.save_matlab_model(model, 'S_pombe.xml')
# CO2 : 516 ; ergosterol: 658 ; H2O : 922 ; ammonium: 1203 ;
# oxygen: 1240 ; phosphate: 1343 ; sulphate: 1523 ; zymosterol : 1693

# to find extracelluar transport reactions
for i in range(len(model.reactions)):
    if len(model.reactions[i].reactants) == 0:
        print("%s : %i" % (model.reactions[i], i))

mant_e = cobra.Metabolite('mant_e', name='Manninotriose', compartment='e')
gal_e = cobra.Metabolite('gal_e', name='Galactose', compartment='e')
H2O_e = cobra.Metabolite('H2O_e', name='Water', compartment='e')
melib_e = cobra.Metabolite('melib_e', name='Melibiose', compartment='e')
raffin_e = cobra.Metabolite('raffin_e', name='Raffinose', compartment='e')
sta_e = cobra.Metabolite('sta_e', name='Stachyose', compartment='e')
GALI_e = cobra.Metabolite('GALI_e', name='Galactinol', compartment='e')
inost_e = cobra.Metabolite('inost_e', name='myo-Inositol', compartment='e')
emp_e = cobra.Metabolite('emp_e', name='Epimelibioise', compartment='e')
man_e = cobra.Metabolite('man_e', name='D-Mannose', compartment='e')
ggl_e = cobra.Metabolite('ggl_e', name='Galactosylglycerol', compartment='e')
glyc_e = cobra.Metabolite('glyc_e', name='Glycerol', compartment='e')
melt_e = cobra.Metabolite('melt_e', name='Melibiitol', compartment='e')
sbtD_e = cobra.Metabolite('sbtD_e', name='D-sorbitol', compartment='e')
GDP_e = cobra.Metabolite('GDP_e', name='GDP', compartment='e')
GMP_e = cobra.Metabolite('GMP_e', name='GMP', compartment='e')
Example #5
0
    def __init__(self,
                 model,
                 Universal=None,
                 threshold=0.05,
                 penalties={
                     "Universal": 1,
                     "Exchange": 1,
                     "Demand": 1
                 },
                 dm_rxns=False,
                 ex_rxns=True):
        cobra.Model.__init__(self, "")
        # store parameters
        self.threshold = threshold
        self.penalties = penalties
        # want to only operate on a copy of Universal so as not to mess up
        # is this necessary?
        if Universal is None:
            Universal = cobra.Model("Universal_Reactions")
        else:
            Universal = Universal.copy()

        # SUX += Exchange (when exchange generator has been written)
        # For now, adding exchange reactions to Universal - could add to a new model called exchange and allow their addition or not....
        if ex_rxns:
            ex_reactions = [x for x in model.reactions if x.startswith('EX_')]
        else:
            ex_reactions = []

        # ADD ALL EXCHANGE REACTIONS TO UNIVERSAL MODEL
        for r in ex_reactions:
            if r.lower_bound >= 0:
                rxn = r.copy()
                #model.remove_reaction(r)
                rxn.id += "_gapfill"
                rxn.lower_bound = -1000
                Universal.add_reaction(rxn)

        if dm_rxns:
            # ADD DEMAND REACTIONS FOR ALL METABOLITES TO UNIVERSAL MODEL
            for m in model.metabolites:
                rxn = Reaction('DM_' + m.id)
                rxn.lower_bound = -1000
                rxn.upper_bound = 1000
                rxn.add_metabolites({m: -1.0})
                Universal.add_reaction(rxn)

        cobra.manipulation.modify.convert_to_irreversible(Universal)

        for rxn in Universal.reactions:
            if rxn.startswith('EX_'):
                rxn.notes["gapfilling_type"] = "Exchange"
            elif rxn.startswith('DM_'):
                rxn.notes["gapfilling_type"] = "Demand"
            else:
                rxn.notes["gapfilling_type"] = "Universal"
        self += model
        self += Universal

        # Add MILP dummy reactions
        v = 1000  # maximum flux in a reaction
        # threshold = 0.05
        dummy_reactions = []
        # all reactions with an index < len(model.reactions) were original
        self.original_reactions = self.reactions[:len(model.reactions)]
        self.added_reactions = self.reactions[len(model.reactions):]

        # add in the dummy reactions for each added reaction
        # a dict will map from each added reaction (the key) to
        # the dummy reaction (the value)
        self._dummy_reaction_map = {}
        for reaction in self.added_reactions:
            dummy_metabolite = cobra.Metabolite("dummy_met_" + reaction.id)
            dummy_metabolite._constraint_sense = "L"
            reaction.add_metabolites({dummy_metabolite: 1})
            the_dummy_reaction = cobra.Reaction("dummy_rxn_" + reaction.id)
            the_dummy_reaction.add_metabolites({dummy_metabolite: -1 * v})
            the_dummy_reaction.lower_bound = 0
            the_dummy_reaction.upper_bound = 1
            the_dummy_reaction.variable_kind = "integer"
            dummy_reactions.append(the_dummy_reaction)
            self._dummy_reaction_map[reaction] = the_dummy_reaction
        self.add_reactions(dummy_reactions)
        # add in the dummy metabolite for the actual objective function
        self.objective_metabolite = cobra.Metabolite(
            "dummy_metabolite_objective_function")
        self.objective_metabolite._constraint_sense = "G"
        self.objective_metabolite._bound = self.threshold
        self._update_objectives()
        # make .add_reaction(s) call the ._add_reaction(s) functions
        self.add_reaction = self._add_reaction
        self.add_reactions = self._add_reactions
Example #6
0
def get_m_model():
    m = cobra.Model("e_coli_ME_M_portion")
    m.compartments = {"p": "Periplasm", "e": "Extra-organism", "c": "Cytosol"}
    compartment_lookup = {v: k for k, v in m.compartments.items()}

    met_info = pandas.read_csv(
        join(ecoli_files_dir, "metabolites.txt"),
        delimiter="\t",
        header=None,
        index_col=0,
        names=["id", "name", "formula", "compartment", "data_source"])
    complex_set = \
        set(get_complex_subunit_stoichiometry("protein_complexes.txt").keys())

    for met_id in met_info.index:
        fixed_id = fix_id(met_id)
        for compartment in met_info.compartment[met_id].split("AND"):
            compartment = compartment.strip()
            if compartment == "No_Compartment":
                print("Assigned %s to c" % met_id)
                compartment = m.compartments["c"]
            new_met = cobra.Metabolite(fixed_id + "_" +
                                       compartment_lookup[compartment])
            new_met.name = met_info.name[met_id]
            new_met.formula = met_info.formula[met_id]
            m.add_metabolites(new_met)

    rxn_info = get_reaction_info_frame('reactions.txt')
    rxn_dict = get_reaction_matrix_dict('reaction_matrix.txt',
                                        complex_set=complex_set)
    for rxn_id in rxn_info.index:
        reaction = cobra.Reaction(rxn_id)
        reaction.name = rxn_info.description[rxn_id]
        for met_id, amount in rxn_dict[rxn_id].items():
            try:
                metabolite = m.metabolites.get_by_id(met_id)
            except KeyError:
                metabolite = cobra.Metabolite(met_id)
            reaction.add_metabolites({metabolite: amount})
        reaction.lower_bound = \
            -1000. if rxn_info.is_reversible[rxn_id] else 0.
        reaction.upper_bound = 1000.
        if rxn_info.is_spontaneous[rxn_id]:
            reaction.gene_reaction_rule = "s0001"
        m.add_reaction(reaction)

    sources_sinks = pandas.read_csv(
        fixpath("reaction_matrix_sources_and_sinks.txt"),
        delimiter="\t",
        header=None,
        names=["rxn_id", "met_id", "compartment", "stoic"],
        index_col=1)

    source_amounts = pandas.read_csv(join(ecoli_files_dir,
                                          "exchange_bounds.txt"),
                                     delimiter="\t",
                                     index_col=0,
                                     names=["met_id", "amount"])

    sources_sinks.index = [fix_id(i) for i in sources_sinks.index]
    source_amounts.index = [fix_id(i) for i in source_amounts.index]

    for met in sources_sinks.index:
        met_id = met + "_" + compartment_lookup[sources_sinks.compartment[met]]
        # EX_ or DM_ + met_id
        reaction_id = sources_sinks.rxn_id[met][:3] + met_id
        reaction = cobra.Reaction(reaction_id)
        m.add_reaction(reaction)
        reaction.add_metabolites({m.metabolites.get_by_id(met_id): -1})
        # set bounds on exchanges
        if reaction.id.startswith("EX_") and met in source_amounts.index:
            reaction.lower_bound = -source_amounts.amount[met]

    return m
Example #7
0
def one_exchange(base):
    rxn = cobra.Reaction('EX_abc_e')
    rxn.add_metabolites({cobra.Metabolite(id="abc_e", compartment='e'): -1})
    rxn.bounds = -1, 5
    base.add_reactions([rxn])
    return base
Example #8
0
    def add_fake_designs(self):
        """ Add a fake design with a parent design """
        model = self.project.model
        project = self.project

        # Phosphoribulokinase reaction
        stoich = dict(
            atp_c=-1.0,
            ru5p__D_c=-1.0,
            adp_c=1.0,
            h_c=1.0,
            rb15bp_c=1.0,
        )

        rb15bp = cobra.Metabolite(id='rb15bp_c', name='D-Ribulose 1,5-bisphosphate', formula='C5H8O11P2', charge=0)
        model.add_metabolites(rb15bp)

        pruk = cobra.Reaction(id="PRUK", name="Phosphoribulokinase reaction", lower_bound=-1000, upper_bound=1000)
        model.add_reactions([pruk])
        pruk.add_metabolites(stoich)

        # Rubisco reaction (Ribulose-bisphosphate carboxylase)
        stoich = {
            "3pg_c": 2.0,
            "rb15bp_c": -1.0,
            "co2_c": -1.0,
            "h2o_c": -1.0,
            "h_c": 2.0
        }

        rubisco = cobra.Reaction(id="RBPC", lower_bound=0, upper_bound=1000.0, name="Ribulose-bisphosphate carboxylase")

        model.add_reactions([rubisco])
        rubisco.add_metabolites(stoich)

        model.genes.get_by_id("b3916").knock_out()
        model.genes.get_by_id("b1723").knock_out()
        model.genes.get_by_id("b1852").knock_out()

        model.reactions.EX_glc__D_e.lower_bound = -10.0
        model.reactions.EX_nh4_e.lower_bound = -1000.0

        project.save_design(model, 'cbb_cycle', 'calvin cycle',
                            description='Reactions necissary for the calvin cycle in ecoli', overwrite=True)

        # Create a child of this design
        model = project.load_design('cbb_cycle')
        reaction = cobra.Reaction(id="HMGCOASi", name="Hydroxymethylglutaryl CoA synthase")

        aacoa = cobra.Metabolite(id="aacoa_c", charge=-4, formula="C25H36N7O18P3S", name="Acetoacetyl-CoA")
        hmgcoa = cobra.Metabolite(id="hmgcoa_c", charge=-5, formula="C27H40N7O20P3S", name="Hydroxymethylglutaryl CoA")

        model.add_metabolites([aacoa, hmgcoa])

        stoich = dict(
            aacoa_c=-1.0,
            accoa_c=-1.0,
            coa_c=1.0,
            h_c=1.0,
            h2o_c=-1.0,
            hmgcoa_c=1.0,
        )

        model.add_reactions([reaction])
        reaction.add_metabolites(stoich)
        reaction.lower_bound = -1000.0
        reaction.upper_bound = 1000.0

        mev__r = cobra.Metabolite(id="mev__R_c", name="R Mevalonate", charge=-1, formula="C6H11O4")
        model.add_metabolites([mev__r])

        reaction = cobra.Reaction(id="HMGCOAR", name="Hydroxymethylglutaryl CoA reductase")
        reaction.lower_bound = -1000.0
        reaction.upper_bound = 1000.0

        stoich = dict(
            coa_c=-1.0,
            h_c=2.0,
            nadp_c=-2.0,
            nadph_c=2.0,
            hmgcoa_c=1.0,
            mev__R_c=-1.0
        )

        model.add_reactions([reaction])

        reaction.add_metabolites(stoich)

        model.add_boundary(mev__r, type='sink')  # add somewhere for mevalonate to go

        project.save_design(model, 'mevalonate_cbb', 'mevalonate production', parent='cbb_cycle',
                            description='Reactions for the production of mevalonate', overwrite=True)

        py_design = """
def gsmdesign_testpy(model, project):
    reaction = model.reactions.get_by_id("ATPM")
    reaction.bounds = (-999, 999)
    return model

gsmdesign_testpy.parent = "mevalonate_cbb"
        """
        ndpath = os.path.join(project.design_path, 'design_fake.py')
        with open(ndpath, 'w+') as desf:
            desf.write(py_design)
Example #9
0
    def __init__(self, model, boundary_species, add_biomass=False):
        """ A class to handle the dynamic optimization based method of dynamic
        flux analysis from [1].

        model: a cobra.Model object.
            Contains the model to be optimized, reaction bounds and objective
            vectors will be preserved.

        boundary_species: a list
            Contains a list of strings specifying the boundary species which
            will be explicity tracked in the dynamic optimization. Biomass
            should be the first entry.

        add_biomass: bool
            Whether or not to attempt to add a `biomass` metabolite to the
            model. If True, will add the metabolite to the reaction specified
            by the objective function.

        ---
        [1] J. L. Hjersted and M. A. Henson, "Optimization of
        Fed-Batch Saccharomyces cerevisiae Fermentation Using Dynamic Flux
        Balance Models," Biotechnol Progress, vol. 22, no. 5, pp. 1239-1248,
        Sep. 2008. 
        """

        if add_biomass:

            biomass = cobra.Metabolite('biomass', compartment='e')
            biomass_rxn = model.objective.keys()[0]
            biomass_rxn.add_metabolites({biomass : 1})
            EX_biomass = cobra.Reaction('EX_biomass')
            EX_biomass.add_metabolites({biomass : -1})
            model.add_reaction(EX_biomass)
            

        self.model = cobra.core.DataframeBasedModel(model)
        self.model.optimize(minimize_absolute_flux=1.0)

        
        # Handle boundary reactions
        self.boundary_species = boundary_species
        all_boundary_rxns = model.reactions.query('system_boundary', 'boundary')

        self.boundary_rxns = []
        for bs in boundary_species:
            rxns = all_boundary_rxns.query(lambda r: r.reactants[0].id in bs)

            assert len(rxns) == 1, (
                "Error finding boundary reactions for {}: ".format(bs) + 
                "{:d} reactions found".format(len(rxns)))

            self.boundary_rxns += [rxns[0].id]

        self.nx = len(boundary_species)
        self.nv = len(self.model.reactions)
        self.nm = len(self.model.metabolites)

        # If tf is left as None, it will be a symbolic variable
        self.tf = None
        self.death_rate = None

        # Initialize the base class
        super(DOAcollocation, self).__init__()
Example #10
0
    FBA_model.objective = {FBA_model.reactions.test_biomass: 1}

    FBA_model.solver = 'glpk'
    solution = FBA_model.optimize()
    if solution.f > 0.0001:
        return 'Success!'
    else:
        return 'Failed :-('


for component in med_components:
    try:
        met = FBA_model.metabolites.get_by_id(component)
    except:
        print('model to be filled has no ' + component + ': Adding it!')
        met = cobra.Metabolite(component)
    try:
        exchange = FBA_model.reactions.get_by_id('EX_' + component)
    except:
        exchange = FBA_model.add_boundary(met)
        print('new exchange reaction added: EX_' + component)
    exch_id = exchange.id
    med[exch_id] = 300

FBA_model.medium = med

##add a proton leak so we don't need to worry about charge balance for each individual metabolite to be checked
##this is NEVER (and should not be) saved back into the SBML file!!
H_extra = FBA_model.metabolites.get_by_id('cpd00067_e0')
H_intra = FBA_model.metabolites.get_by_id('cpd00067_c0')
H_transport = cobra.Reaction('proton_leak')
Example #11
0
def run_test_suite(json_model, update='start'):
    """
    Runs a series of tests to determine if any updates significantly impact the metabolic model
    :param json_model: COBRApy-compliant model in JSON format
    :param update: the type of update that is made
    :return: a tsv file chronicling the model update test results
    """
    model = cobra.io.load_json_model(
        json_model)  # iEK1008.json: Griffin 2011 media pre-set in model

    model_info = {
        'Model_ID': model.id,
        'Model_Update': update,
        'Total_Metabolites': str(len(model.metabolites)),
        'Total_Reactions': str(len(model.reactions)),
        'Total_Genes': str(len(model.genes)),
        'Total_Compartments': str(len(model.compartments.keys())),
        'Metabolic_Coverage': str(len(model.reactions) / len(model.genes))
    }

    try:
        model.objective = 'BIOMASS__2'
    except ValueError:
        try:
            model.objective = 'biomass_iEK1008_60atp'
            model.reactions.get_by_id(
                'biomass_iEK1008_60atp').upper_bound = 1000
        except ValueError:
            biomass_rxns = [
                rxn.id for rxn in model.reactions
                if 'biomass' in rxn.id.lower()
            ]
            model.objective = biomass_rxns[0]

    to_balance = [
        rxn.id for rxn in model.reactions if len(rxn.check_mass_balance()) > 0
        if 'EX_' not in rxn.id and 'DM_' not in rxn.id
        and 'biomass' not in rxn.id.lower()
    ]

    mets_no_rxn = [
        met.id for met in model.metabolites if len(met.reactions) == 0
    ]

    try:
        df_fva = cobra.flux_analysis.flux_variability_analysis(
            model, fraction_of_optimum=1.0)
    except cobra.exceptions.Infeasible:  # needed for models without pre-set media or those that cannot grow
        model.medium = {}  # clears any pre-set media

        for rxn_id, uptake_rate in media.iEK_griffinEssen.items(
        ):  # loads Griffin media
            model.reactions.get_by_id(rxn_id).lower_bound = uptake_rate

        df_fva = cobra.flux_analysis.flux_variability_analysis(
            model, fraction_of_optimum=1.0)

    min_value = 0.99999 * df_fva['minimum'].min()
    max_value = 0.99999 * df_fva['maximum'].max()
    unbound_rxns = (df_fva[df_fva['minimum'] < min_value] +
                    df_fva[df_fva['maximum'] > max_value]).index.to_list()

    model_consistency = {
        'Imbalanced_Reactions': str(len(to_balance)),
        'Disconnected_Metabolites': str(len(mets_no_rxn)),
        'Unbound_Reactions_in_Medium': str(len(unbound_rxns))
    }

    blocked_rxns = cobra.flux_analysis.variability.find_blocked_reactions(
        model, open_exchanges=True)

    # single_rxn_mets not the same as orphan & dead-end metabolites --> see updated model results in https://memote.io/
    single_rxn_mets = [
        met.id for met in model.metabolites if len(met.reactions) == 1
    ]

    model_network_topology = {
        'Blocked_Reactions': str(len(blocked_rxns)),
        'Single_Reaction_Metabolites': str(len(single_rxn_mets))
    }

    # clears model of active exchange reactions (i.e. removes 'preset' media); same as model.medium = {}
    for rxn in model.reactions:
        if 'EX_' in rxn.id:
            rxn.lower_bound = 0

    xtps = {
        'ATPM': 'Erroneous ATP Flux',
        'NTP3': 'Erroneous GTP Flux',
        'ctp_c': 'Erroneous CTP Flux',
        'utp_c': 'Erroneous UTP Flux'
    }

    xtp_yields = 0
    model_energy_cycles = {}

    for rxn_or_met in xtps.keys():
        if '_c' not in rxn_or_met:
            model.reactions.get_by_id(
                rxn_or_met).lower_bound = 0  # Gsmodutils: = 1
            model.objective = rxn_or_met
        elif '_c' in rxn_or_met:
            drain_rxn = cobra.Reaction(f'DR_{rxn_or_met}')
            model.add_reactions([drain_rxn])
            drain_rxn.add_metabolites({
                cobra.Metabolite(rxn_or_met):
                -1.0,
                cobra.Metabolite('h2o_c'):
                -1.0,
                cobra.Metabolite('h_c'):
                1.0,
                cobra.Metabolite('pi_c'):
                1.0,
                cobra.Metabolite(rxn_or_met.replace('tp_c', 'dp_c')):
                1.0
            })
            drain_rxn.lower_bound = 0
            drain_rxn.upper_bound = 1000
            model.objective = f'DR_{rxn_or_met}'

        xtp_yield = model.optimize(
        ).objective_value  # ATPM: closed bounds = 0 // Griffin = 10.875 mmol ATP gDW-1 hr-1
        xtp_yields += xtp_yield

    model_energy_cycles['Erroneous_xTP_Flux'] = str(xtp_yields)

    model_growth = {}
    mtb_media = {
        'Biomass_Flux_in_iEK_m7H10': media.iEK_m7H10,
        'Biomass_Flux_in_m7H10': media.m7H10,
        'ATPM_Flux_in_iEK_m7H10': media.iEK_m7H10,
        'ATPM_Flux_in_m7H10': media.m7H10
    }

    for name, mtb_medium in mtb_media.items():
        model.medium = {}

        for ex_rxn_id, uptake_rate in mtb_medium.items():
            try:
                model.reactions.get_by_id(ex_rxn_id).lower_bound = uptake_rate
            except KeyError:  # bypasses exchange reactions in media that are not present in model (e.g. EX_zn2_e)
                continue

        if 'Biomass' in name:
            model.objective = 'BIOMASS__2'
            model_growth[name] = str(model.optimize().objective_value)
        elif 'ATPM' in name:
            model.objective = 'ATPM'
            model_growth[name] = str(model.optimize().objective_value)

    model_tests = {
        **model_info,
        **model_consistency,
        **model_network_topology,
        **model_energy_cycles,
        **model_growth
    }

    header = list(model_tests.keys())
    model_results = list(model_tests.values())

    file_path = '../results/'
    file_name = 'iEK1008_test_suite.tsv'  # f'{model.id}': will write different files when model ID changes

    if file_name not in os.listdir(file_path):
        update_file = open(file_path + file_name, 'w')
        update_file.write('\t'.join(header) + '\n')
        update_file.write('\t'.join(model_results) + '\n')
    else:
        update_file = open(file_path + file_name, 'a')
        update_file.write('\t'.join(model_results) + '\n')
def create_metabolite_from_dict(m_dict):
    metabolite = cobra.Metabolite(m_dict['id'])
    metabolite.name = m_dict['name']
    metabolite.charge = m_dict['charge']
    metabolite.compartment = m_dict['compartment']
    return metabolite
Example #13
0
# TODO: Get the actual number
nt_ratios = {'u':0.25,
             'a':0.25,
             'g':0.25,
             'c':0.25,
             }

rna_nucleotides = {'u':'ura_c',
                   'g':'gua_c',
                   'a':'ade_c',
                   'c':'csn_c'}

coupling_dict = dict()

# Add cystein -> selenocystein transformation for convenience
selcys = cobra.Metabolite(id='selcys__L_c', compartment = 'c')
selcys_rxn = cobra.Reaction(id='PSEUDO_selenocystein_synthase',
                            name='PSEUDO Selenocystein_Synthase')
selcys_rxn.add_metabolites({ecoli.metabolites.cys__L_c:-1,
                            selcys:+1})
ecoli.add_reactions([selcys_rxn])

# Prot degradation
# http://www.jbc.org/content/246/22/6956.full.pdf
# The total amount of enzyme undergoing degrada- tion (2 to 7%) was the same
# during growth and during various kinds of starvation.
kdeg_low, kdeg_up = 0.02, 0.07
kdeg_enz = (kdeg_low + kdeg_up)/2

# From :
# http://book.bionumbers.org/how-fast-do-rnas-and-proteins-degrade/
Example #14
0
def metabolite_registry():
    registry = {}
    registry["g6p_c"] = cobra.Metabolite("g6p_c", compartment="c")
    registry["g6p_c"].annotation["kegg.compound"] = "C00668"
    registry["glc__D_c"] = cobra.Metabolite("glc__D_c", compartment="c")
    registry["glc__D_c"].annotation["kegg.compound"] = "C00267"
    registry["h2o_c"] = cobra.Metabolite("h2o_c", compartment="c")
    registry["h2o_c"].annotation["kegg.compound"] = "C00001"
    registry["pi_c"] = cobra.Metabolite("pi_c", compartment="c")
    registry["pi_c"].annotation["kegg.compound"] = "C00009"
    registry["h2o_c_list"] = cobra.Metabolite("h2o_c", compartment="c")
    registry["h2o_c_list"].annotation["kegg.compound"] = [
        'C00001', 'C01328', 'D00001', 'D03703', 'D06322']
    registry["o2_c_list"] = cobra.Metabolite("o2_c", compartment="c")
    registry["o2_c_list"].annotation["kegg.compound"] = ['C00007', 'D00003']
    registry["h2_c_list"] = cobra.Metabolite("h2_c", compartment="c")
    registry["h2_c_list"].annotation["kegg.compound"] = ['C00282']
    registry["h2o_c_name"] = cobra.Metabolite(
        "h2o_c", name="Water", compartment="c")
    registry["o2_c_name"] = cobra.Metabolite(
        "o2_c", name="Oxygen", compartment="c")
    registry["h2_c_name"] = cobra.Metabolite(
        "h2_c", name="Hydrogen", compartment="c")
    registry["whack_c"] = cobra.Metabolite(
        "whack_c", name="Whack", compartment="c")
    registry["odd_c"] = cobra.Metabolite("odd_c", name="Odd", compartment="c")
    registry["unknown_c"] = cobra.Metabolite("unknown_c", compartment="c")
    return registry
Example #15
0
def read_simpheny(baseName,
                  min_lower_bound=-1000,
                  max_upper_bound=1000,
                  maximize_info=True):
    r"""Imports files exported from a SimPheny simulation as a cobra model.

    .. warning:: Use with caution. This is a legacy import function, and
        errors have been observed in the converted gene-reaction rules.

    Parameters
    ----------
    baseName : str
        The filepath to the exported SimPheny files without any of the
        extensions. On Windows, it helps if baseName is a raw string
        (i.e. r"Path\\to\\files")
    min_lower_bound, max_upper_bound : float or int, optional
        The bounds on the lower and upper bounds of fluxes in model.
    maximize_info : bool, optional
        An optional boolean keyword argument. If True, then an attempt
        will be made to parse the gpr and metabolite info files, and the
        function will take a little bit longer.

    Returns
    -------
    model : cobra.Model
        the imported simpheny model

    """

    # check to make sure the files can be read
    if not (isfile(baseName + ".met") and isfile(baseName + ".rxn")
            and isfile(baseName + ".sto")):
        # try again with modifying the baseName
        baseName = baseName.encode("string-escape")
        if not (isfile(baseName + ".met") and isfile(baseName + ".rxn")
                and isfile(baseName + ".sto")):
            raise (IOError, "Input file(s) not found")
    model = cobra.Model("SimPheny import from " + baseName)
    # read in metabolite file
    metfile = _open_and_skip_header(baseName + ".met")
    metabolites = []
    for line in metfile:
        if len(line) == 0:
            break
        metabolite = cobra.Metabolite(id=line[1],
                                      name=line[2],
                                      compartment=line[3])
        if maximize_info:
            compartment_search = re.findall("\([a-z]\)$", metabolite.id)
            if compartment_search != []:
                metabolite.compartment = compartment_search[0][1]
                model.compartments[metabolite.compartment] = line[3]
        metabolites.append(metabolite)
    model.add_metabolites(metabolites)
    # scalefunc will limit the maximum and minumum fluxes
    scalefunc = lambda x: max(min(max_upper_bound, x), min_lower_bound)
    # read in reaction file
    reaction_file = _open_and_skip_header(baseName + ".rxn")
    reactions = []
    for line in reaction_file:
        if len(line) == 0:
            break
        the_reaction = cobra.Reaction()
        the_reaction.id = line[1]
        the_reaction.name = line[2]
        if line[3].lower() == "reversible":
            the_reaction.reversibility = 1
        elif line[3].lower() == "irreversible":
            the_reaction.reversibility = 0
        the_reaction.lower_bound = scalefunc(float(line[4]))
        the_reaction.upper_bound = scalefunc(float(line[5]))
        the_reaction.objective_coefficient = float(line[6])
        reactions.append(the_reaction)
    model.add_reactions(reactions)
    # read in S matrix
    Sfile = _open_and_skip_header(baseName + ".sto")
    S = []
    for i, line in enumerate(Sfile):
        if len(line) == 0:
            break
        the_metabolite = metabolites[i]
        for j, ns in enumerate(line):
            n = float(ns)
            if n != 0:
                model.reactions[j].add_metabolites({the_metabolite: n})
    # attempt to read in more data
    infofilepath = baseName + "_cmpd.txt"
    if maximize_info and isfile(infofilepath):
        infofile = open(infofilepath, "r")
        infofile.readline()  # skip the header
        infocsv = csv.reader(infofile)
        for row in infocsv:
            found = _find_metabolites_by_base(row[0], model.metabolites)
            for found_metabolite in found:
                found_metabolite.formula = row[2]
                found_metabolite.parse_composition()
                found_metabolite.charge = row[4]
                found_metabolite.notes = {}
                found_metabolite.notes["KEGG_id"] = row[8]
                found_metabolite.notes["CAS"] = row[5]
                found_metaboltie.notes["review status"] = row[3]
        infofile.close()
    gpr_filepath = baseName + "_gpr.txt"
    if maximize_info and isfile(gpr_filepath):
        warn("SimPheny export files may have errors in the gpr.")
        # Using this may be risky
        gpr_file = open(gpr_filepath, "r")
        gpr_file.readline()  # skip the header
        gpr_csv = csv.reader(gpr_file)
        for row in gpr_csv:
            the_reaction = model.reactions[model.reactions.index(row[0])]
            the_reaction.gene_reaction_rule = row[5]
            the_reaction.parse_gene_association()
        gpr_file.close()
    # model.update()
    return model
ex_reaction_ids = [x.id for x in model.reactions if x.id.startswith("EX_")]
for ex_reaction_id in ex_reaction_ids:
    if model.reactions.get_by_id(ex_reaction_id).metabolites == {}:
        model.remove_reactions([ex_reaction_id])

print(
    "Add periplasmic metabolite for all metabolties in EX_ reactions ending with _c..."
)
ex_c_reaction_ids = [
    x.id for x in model.reactions
    if x.id.startswith("EX_") and x.id.endswith("_c")
]
for ex_c_reaction_id in ex_c_reaction_ids:
    reaction = model.reactions.get_by_id(ex_c_reaction_id)
    metabolite = list(reaction.metabolites.keys())[0]
    new_p_metabolite = cobra.Metabolite(id=metabolite.id.replace("_c", "_p"),
                                        compartment="p")
    reaction.add_metabolites({new_p_metabolite: 1})
    new_ex_reaction = cobra.Reaction(id="EX_" + new_p_metabolite.id,
                                     lower_bound=reaction.lower_bound,
                                     upper_bound=reaction.upper_bound)
    new_ex_reaction.add_metabolites({new_p_metabolite: -1})
    model.add_reactions([new_ex_reaction])
    reaction.id = "Transport_c_to_p_" + metabolite.id.replace("_c", "")

print("Get all reaction IDs ending with Ex and Up...")
ex_reaction_ids = [x.id for x in model.reactions if x.id.endswith("Ex")]
up_reaction_ids = [x.id for x in model.reactions if x.id.endswith("Up")]
all_exchange_ids = ex_reaction_ids + up_reaction_ids


class ExchangedMetabolite:
Example #17
0
exchg_reaction_ids = [
    x.id for x in model.reactions if x.id.startswith("EXCHG_")
]
for exchg_reaction_id in exchg_reaction_ids:
    reaction = model.reactions.get_by_id(exchg_reaction_id)
    if ("_adp_" in reaction.id) or ("_pi_" in reaction.id) or (
            "_h_" in reaction.id) or ("_h2o_" in reaction.id):
        continue
    if "ecoli1" in reaction.id:
        id_addition = "ecoli1"
    else:
        id_addition = "ecoli2"
    if ((reaction.lower_bound == 0) and (reaction.upper_bound == 0)):
        print(reaction.id)
        new_pseudo_metabolite = cobra.Metabolite(id=reaction.id +
                                                 "_PSEUDOMET_REV",
                                                 compartment="exchg")
        reaction.add_metabolites({new_pseudo_metabolite: -1})
        new_pseudo_reaction_1 = cobra.Reaction(id=reaction.id.replace(
            "EXCHG_", "").replace("ecoli1_", "").replace("ecoli2_", "") +
                                               "_PSEUDOREAC1_REV_" +
                                               id_addition,
                                               lower_bound=0,
                                               upper_bound=float("inf"))
        new_pseudo_reaction_1.add_metabolites({
            new_pseudo_metabolite: 1,
        })
        new_pseudo_reaction_2 = cobra.Reaction(id=reaction.id.replace(
            "EXCHG_", "").replace("ecoli1_", "").replace("ecoli2_", "") +
                                               "_PSEUDOREAC2_REV_" +
                                               id_addition,
Example #18
0
    def add_to_model(self, model, copy=False, add_missing=True):
        """
        Add this design to a given cobra model
        :param model:
        :param copy:
        :param add_missing: add missing metabolites to the model
        :return:
        """
        if not isinstance(model, cobra.Model):
            raise TypeError('Expected cobra model')

        mdl = model
        if copy:
            mdl = model.copy()

        # Load parent design first
        if self.parent is not None:
            self.parent.add_to_model(mdl)

        mdl.design = self

        if self.is_pydesign:
            try:
                mdl = self.design_func(mdl, self.project)
            except Exception as ex:
                raise DesignError("Function execution error {}".format(ex))

            return mdl

        # Add new or changed metabolites to model
        for metabolite in self.metabolites:
            # create new metabolite object if its not in the model already
            if metabolite['id'] in mdl.metabolites:
                metab = mdl.metabolites.get_by_id(metabolite['id'])
            else:
                metab = cobra.Metabolite()

            # Doesn't check any of these properties for differences, just update them
            metab.id = metabolite['id']
            metab.name = metabolite['name']
            metab.charge = metabolite['charge']
            metab.formula = metabolite['formula']
            metab.notes = metabolite['notes']
            metab.annotation = metabolite['annotation']
            metab.compartment = metabolite['compartment']

            if metab.id not in mdl.metabolites:
                mdl.add_metabolites([metab])

        # Add new or changed reactions to model
        for rct in self.reactions:
            if rct['id'] in mdl.reactions:
                reaction = mdl.reactions.get_by_id(rct['id'])
                reaction.remove_from_model()

            reaction = cobra.Reaction()
            reaction.id = rct['id']

            reaction.name = rct['name']
            reaction.lower_bound = rct['lower_bound']
            reaction.upper_bound = rct['upper_bound']

            reaction.gene_reaction_rule = rct['gene_reaction_rule']
            reaction.subsystem = rct['subsystem']
            reaction.name = rct['name']

            mdl.add_reactions([reaction])
            reaction = mdl.reactions.get_by_id(reaction.id)

            metabolites = dict([(str(x), v)
                                for x, v in rct['metabolites'].items()])

            if add_missing:
                for mid in metabolites:
                    try:
                        mdl.metabolites.get_by_id(mid)
                    except KeyError:
                        metab = cobra.Metabolite(id=mid)
                        mdl.add_metabolites(metab)

            reaction.add_metabolites(metabolites)
            reaction.objective_coefficient = rct['objective_coefficient']

        # delete removed metabolites/reactions
        for rtid in self.removed_reactions:
            try:
                reaction = mdl.reactions.get_by_id(rtid)
                reaction.remove_from_model()
            except KeyError:
                pass

        for metid in self.removed_metabolites:
            try:
                met = mdl.metabolites.get_by_id(metid)
                met.remove_from_model()
            except KeyError:
                pass
        mdl.id += "::{}".format(self.id)

        # Add gene annotation
        for gene in self.genes:

            try:
                gobj = model.genes.get_by_id(gene['id'])
            except KeyError:
                # genes should already be contained in the model if they have a reaction relationship
                # However, tolerate bad designs
                continue
            gobj.name = gene['name']
            gobj.functional = gene['functional']
            gobj.annotation = gene['annotation']
            gobj.notes = gene['notes']

        return mdl
def create_smoment_model_reaction_wise(
        model: cobra.Model,
        output_sbml_name: str,
        project_folder: str,
        project_name: str,
        excluded_reactions: List[str],
        type_of_default_kcat_selection: str = "median") -> None:
    """Adds proteomic constraints according to sMOMENT to the given stoichiometric model and stores it as SBML.

    Arguments
    ----------

    * model: cobra.Model ~ A cobra Model representation of the metabolic network. This model will
      be changed using cobrapy functions in order to add the proteomic constraints.
    * output_sbml_name: str ~ The base name of the created SBML.
    * project_folder: str ~ The folder in which the spreadsheets and JSONs with the model's supplemental
      data can be found.
    * project_name: str ~ The sMOMENTed model creation's name, which will be added at the beginning
      of the created SBML's name.
    * excluded_reactions: List[str] ~ A string list of reaction IDs (the 'reverse' and 'forward'
      name additions must not be added, i.e. for 'ACALD_forward' just 'ACALD' has to be given) to
      which no kcat shall be added. Typically used for gas exchange reactions such as 'CO2tex'.
    * type_of_default_kcat_selection: str ~ The type of selection of default kcat values. Can be "mean",
      "median" or "random". Is "median" by default.

    Output
    ----------
    An SBML in the given folder with the given name, which describes the given stoichiometric model
    enhanced by the protein constraint introduction with this function.
    """
    # Standardize project folder
    project_folder = standardize_folder(project_folder)

    # Set folder path for newly created SBML and name for the reaction ID addition (added at the end,
    # and used in order to have a programatically convinient way to separate additions such as 'reverse'
    # from the 'actual' reaction ID).
    basepath: str = project_folder + project_name
    id_addition: str = "_TG_"

    # READ REACTIONS<->KEGG ID XLSX
    protein_id_mass_mapping: Dict[str, float] = json_load(
        basepath + "_protein_id_mass_mapping.json")

    # Load protein data XLSX
    protein_id_concentration_mapping, p_total, unmeasured_protein_fraction, mean_saturation = \
        read_protein_data_xlsx(basepath)

    # Read enzyme stoichiometries xlsx
    reaction_id_gene_rules_mapping, reaction_id_gene_rules_protein_stoichiometry_mapping = \
        read_enzyme_stoichiometries_xlsx(basepath)

    # Calculate p_measured
    p_measured = get_p_measured(protein_id_concentration_mapping,
                                protein_id_mass_mapping)

    # Split reactions with measured enzymes
    model, reaction_id_gene_rules_mapping, reaction_id_gene_rules_protein_stoichiometry_mapping = \
        get_model_with_separated_measured_enzyme_reactions(model,
                                                           protein_id_concentration_mapping,
                                                           reaction_id_gene_rules_mapping,
                                                           reaction_id_gene_rules_protein_stoichiometry_mapping,
                                                           excluded_reactions,
                                                           protein_id_mass_mapping)

    # Make model irreversible, separating all reversible reactions to which a gene rule is given
    # in order to save some reactions.
    model = get_irreversible_model(model, id_addition)

    # Add prot_pool reaction according to the given protein pool values
    model, prot_pool_metabolite = add_prot_pool_reaction(
        model, id_addition, p_total, p_measured, unmeasured_protein_fraction,
        mean_saturation)

    # Read reaction <-> kcat mapping :-)
    reactions_kcat_mapping_database = json_load(
        basepath + "_reactions_kcat_mapping_combined.json")

    # sMOMENT :D
    # Get all kcats which are not math.nan and calculate the median of them, which will be used as default kcat
    all_kcats = [x["forward"] for x in reactions_kcat_mapping_database.values()] + \
                [x["reverse"] for x in reactions_kcat_mapping_database.values()]
    all_kcats = [x for x in all_kcats if not math.isnan(x)]

    if type_of_default_kcat_selection == "median":
        default_kcat = statistics.median(all_kcats)
    elif type_of_default_kcat_selection == "mean":
        default_kcat = statistics.mean(all_kcats)
    elif type_of_default_kcat_selection == "random":
        default_kcat = random.choice(all_kcats)
    else:
        print(
            'ERROR: Argument type_of_default_kcat_selection must be either "median", "mean" or "random".'
        )
        sys.exit(-1)

    print(f"Default kcat is: {default_kcat}")

    # Get all reaction IDs of the given model
    model_reaction_ids = [x.id for x in model.reactions]

    # Add measured enzyme pseudo-metabolites and pseudo-reactions
    for protein_id in protein_id_concentration_mapping.keys():
        new_metabolite = cobra.Metabolite(
            id="ENZYME_" + protein_id,
            name="Pseudo-metabolite of protein " + protein_id,
            compartment="sMOMENT")
        max_protein_concentration = protein_id_concentration_mapping[
            protein_id]
        new_reaction = cobra.Reaction(
            id="ENZYME_DELIVERY_" + protein_id,
            name="Delivery reaction of pseudo-metabolite " + protein_id,
            lower_bound=0,
            upper_bound=max_protein_concentration)
        new_reaction.add_metabolites({new_metabolite: 1})
        model.add_reactions([new_reaction])

    # Main loop :D, add enzyme constraints to reactions \o/
    for model_reaction_id in model_reaction_ids:
        # Get the reaction and split the ID at the ID addition
        reaction = model.reactions.get_by_id(model_reaction_id)
        splitted_id = reaction.id.split(id_addition)

        # If the reaction has no name, ignore it
        if splitted_id[0] == "":
            continue
        # Take the reaction ID from the first part of the split
        reaction_id = splitted_id[0]
        # Remove GPRSPLIT name addition from reactions with measured protein concentrations
        if "_GPRSPLIT_" in reaction_id:
            reaction_id = reaction_id.split("_GPRSPLIT_")[0]

        # If the reaction has no associated enzyme stoichiometries, ignore it
        if reaction_id not in list(reaction_id_gene_rules_mapping.keys()):
            continue
        # If the reaction has no gene rule, ignore it
        gene_rule = reaction_id_gene_rules_mapping[reaction_id]
        if gene_rule == [""]:
            continue
        # If the reaction is manually excluded, ignore it
        if reaction_id in excluded_reactions:
            continue

        # Check if all proteins in the reaction's gene rule have a found mass
        # This is not the case for e.g. spontaneous reactions which often get the pseudo-enzyme 's0001'
        all_available = True
        for enzyme in gene_rule:
            if type(enzyme) == str:
                if enzyme not in list(protein_id_mass_mapping.keys()):
                    print(enzyme)
                    all_available = False
                    break
            else:
                for enzyme_id in enzyme:
                    if enzyme_id not in list(protein_id_mass_mapping.keys()):
                        all_available = False
                        break
        # If not all of the mass-checked enzymes have a found mass, ignore this reaction
        if not all_available:
            continue

        # Retrieve the reaction's forward and reverse kcats from the given reaction<->kcat database
        if reaction_id in reactions_kcat_mapping_database.keys():
            forward_kcat = reactions_kcat_mapping_database[reaction_id][
                "forward"]
            reverse_kcat = reactions_kcat_mapping_database[reaction_id][
                "reverse"]
        # If the reaction is not in the database, set the default kcat
        else:
            forward_kcat = default_kcat
            reverse_kcat = default_kcat

        # If the given reaction<->kcat database contains math.nan as the reaction's kcat,
        # set the default kcat as math.nan means that no kcat could be found.
        if math.isnan(forward_kcat):
            forward_kcat = default_kcat
        if math.isnan(reverse_kcat):
            reverse_kcat = default_kcat

        # Add the given forward or reverse kcat is the reaction was
        # splitted due to its reversibility.
        # If the reaction is not splitted, add the forward kcat (this
        # is the only possible direction for non-splitted=non-reversible
        # reactions)
        if model_reaction_id.endswith(id_addition + "forward"):
            reaction_kcat = forward_kcat
        elif model_reaction_id.endswith(id_addition + "reverse"):
            reaction_kcat = reverse_kcat
        else:
            reaction_kcat = forward_kcat

        # Add protein pool pseudo-metabolite depending on isozyme complex presence
        # List of selectable MW/kcat stoichiometries (the most conservative constraint will be chosen)
        stoichiometries: List[float] = []
        # List of enzyme names and stoichiometries (semicolon-separated) for a console report
        stoichiometry_enzyme_name_list: List[str] = []
        for isozyme_id in gene_rule:
            # If it's not a complex :O...
            if type(isozyme_id) is str:
                # ...get the reaction ID without the additions...
                reaction_id = reaction_id.split("_TG_")[0]

                # ...get the number of units for this protein...
                number_units = reaction_id_gene_rules_protein_stoichiometry_mapping[
                    reaction_id][isozyme_id][isozyme_id]
                stoichiometry = number_units
                # ...and determine the protein pool stoichiometry by
                # 1) Multiplying the number of units for this protein with its mass (converted from kDa to mDa, since the reaction
                #    flux is defined for mmol/(gDW*h) and not mol/(gDW*h))
                stoichiometry *= (protein_id_mass_mapping[isozyme_id] / 1000)
                # 2) Dividing it with the reaction's kcat (converted from 1/s to 1/h)
                stoichiometry /= (reaction_kcat * 3600)
                # 3) Setting the right direction (educt)
                stoichiometry *= -1
                stoichiometries.append(stoichiometry)
                stoichiometry_enzyme_name_list.append(isozyme_id + ";" +
                                                      str(number_units))

                # Add proteomics constraints
                if isozyme_id in protein_id_concentration_mapping.keys():
                    enzyme_pseudo_metabolite = model.metabolites.get_by_id(
                        "ENZYME_" + isozyme_id)
                    stoichiometry = reaction_id_gene_rules_protein_stoichiometry_mapping[
                        reaction_id][isozyme_id][isozyme_id]
                    stoichiometry *= 1 / (reaction_kcat * 3600)
                    stoichiometry *= -1
                    reaction.add_metabolites(
                        {enzyme_pseudo_metabolite: stoichiometry})
            # If it is a complex :O...
            else:
                # ...convert the complex IDs to a hashable tuple (used for the stoichiometry selection)...
                isozyme_id = tuple(isozyme_id)
                stoichiometry = 0

                # ...go through each single ID of the complex...
                stoichiometry_enzyme_name_list.append("")
                for single_id in isozyme_id:
                    # ...get the reaction ID without additions...
                    reaction_id = reaction_id.split("_TG_")[0]

                    # ...get the number of units for this protein...
                    number_units = reaction_id_gene_rules_protein_stoichiometry_mapping[
                        reaction_id][isozyme_id][single_id]
                    single_stoichiometry = number_units
                    # ...and determine the protein pool stoichiometry addition by
                    # 1) Multiplying the number of units for this protein with its mass (converted from kDa to Da)
                    single_stoichiometry *= (
                        protein_id_mass_mapping[single_id] / 1000)
                    # 2) Dividing it with the reaction's kcat (converted from 1/s to 1/h)
                    single_stoichiometry /= (reaction_kcat * 3600)
                    # 3) Setting the right direction (educt)
                    single_stoichiometry *= -1
                    # 4) and add it to the complex's stoichiometry
                    stoichiometry += single_stoichiometry
                    # Add name of current single ID
                    stoichiometry_enzyme_name_list[-1] += single_id + \
                        ";" + str(number_units) + " "
                stoichiometry_enzyme_name_list[
                    -1] = stoichiometry_enzyme_name_list[-1].rstrip()
                # Add to list of stoichiometries
                stoichiometries.append(stoichiometry)

                # Add proteomics constraints
                for single_id in isozyme_id:
                    if single_id in protein_id_concentration_mapping.keys():
                        enzyme_pseudo_metabolite = model.metabolites.get_by_id(
                            "ENZYME_" + single_id)
                        stoichiometry = reaction_id_gene_rules_protein_stoichiometry_mapping[
                            reaction_id][isozyme_id][single_id]
                        stoichiometry *= 1 / (reaction_kcat * 3600)
                        stoichiometry *= -1
                        reaction.add_metabolites(
                            {enzyme_pseudo_metabolite: stoichiometry})

        # Take the maximal stoichiometry (i.e., the one with the least cost since this one will usually be prefered
        # anyway in an FBA).
        metabolites = {}
        max_stoichiometry = max(stoichiometries)
        metabolites[prot_pool_metabolite] = max_stoichiometry
        reaction.add_metabolites(metabolites)
        selected_enzyme = stoichiometry_enzyme_name_list[stoichiometries.index(
            max_stoichiometry)]

        # Print report of selected kcat and molecular weight for this reaction
        print("Reaction: ", model_reaction_id)
        print("Selected kcat: ", reaction_kcat)
        print("Selected molecular weight (kDa): ", end="")
        if " " in selected_enzyme:  # Multiple enzymes
            mass_sum = .0
            for single_enzyme in selected_enzyme.split(" "):
                enzyme_name = single_enzyme.split(";")[0]
                enzyme_unit_number = float(single_enzyme.split(";")[1])
                mass_sum += protein_id_mass_mapping[enzyme_name] * \
                    enzyme_unit_number
            print(mass_sum)
        else:  # Single enzyme
            enzyme_name = selected_enzyme.split(";")[0]
            enzyme_unit_number = float(selected_enzyme.split(";")[1])
            print(protein_id_mass_mapping[enzyme_name] * enzyme_unit_number)

    # Output as SBML (without constraints due to cobrapy limitations)
    cobra.io.write_sbml_model(model, project_folder + output_sbml_name)
Example #20
0
    def _make_dictionaries(self):
        self.cofactor_metabolites_dict = {
            'nadph':
            self.model.metabolites.get_by_id('nadph_c'),
            'nadp':
            self.model.metabolites.get_by_id('nadp_c'),
            'h2o':
            self.model.metabolites.get_by_id('h2o_c'),
            'coa':
            self.model.metabolites.get_by_id('coa_c'),
            'co2':
            self.model.metabolites.get_by_id('co2_c'),
            'h+':
            self.model.metabolites.get_by_id('h_c'),
            'sam':
            self.model.metabolites.get_by_id('amet_c'),
            'sah':
            self.model.metabolites.get_by_id('ahcys_c'),
            'mxmal':
            cobra.Metabolite('mxmal_c',
                             formula='C14H20N6O5S',
                             name='Methoxymalonyl-ACP',
                             compartment='c'),
            '4hbf':
            cobra.Metabolite('4hbf_c',
                             formula='X',
                             name='4-hydroxy-benzoyl-formate',
                             compartment='c'),
            'hpg':
            cobra.Metabolite('4hpg_c',
                             formula='X',
                             name='4-hydroxy-phenyl-glycine',
                             compartment='c'),
            'dpg':
            cobra.Metabolite('dpg_c',
                             formula='X',
                             name='dihydroxy-phenyl-glycine',
                             compartment='c'),
            'bht':
            cobra.Metabolite('bht_c',
                             formula='X',
                             name='beta-hydroxy-tyrosine',
                             compartment='c'),
            'pip':
            cobra.Metabolite('Lpipecol_c',
                             formula='X',
                             name='pipecolic acid',
                             compartment='c'),
            'fatty_acid_X':
            cobra.Metabolite(
                'fatty_acid_X_c',
                formula='X',
                name='generic fatty acid for acylation in NRPS initiation',
                compartment='c'),
            'abu':
            cobra.Metabolite('2abu_c',
                             formula='X',
                             name='2-aminobutyrate',
                             compartment='c'),
            'ahba':
            cobra.Metabolite(
                'ahba_c',
                formula='C7H7NO3',
                name='3-Amino-5-hydroxybenzoate',
                compartment='c'
            ),  # https://www.genome.jp/dbget-bin/www_bget?C12107
            'bafA':
            cobra.Metabolite('bafilomycinA1_c',
                             formula='X',
                             name='Bafilomycin A1',
                             compartment='c'),
            'bafB':
            cobra.Metabolite('bafilomycinB1_c',
                             formula='X',
                             name='Bafilomycin B1',
                             compartment='c'),
            'fumamp':
            cobra.Metabolite('fumamp_c',
                             formula='X',
                             name='Fumaryl-AMP',
                             compartment='c'),
            'mxacp':
            cobra.Metabolite(
                'mxacp_c',
                formula='X',
                name='methoxymalonate specific acyl carrier protein',
                compartment='c'),
            'c5n':
            cobra.Metabolite('c5n_c',
                             formula='X',
                             name='2-amino-3-hydroxycyclopent-2-enone',
                             compartment='c'),
            'fumamp_pk':
            cobra.Metabolite('fumamp__pk_c',
                             formula='X',
                             name='Fumaryl-AMP bound to polyketide',
                             compartment='c'),
            'final_product':
            cobra.Metabolite('final_product_c',
                             formula='X',
                             name='Final product',
                             compartment='c'),
            '3mbm':
            cobra.Metabolite('3mbmcoa_c',
                             formula='C8H14O4',
                             name='(3-Methylbutyl)malonic acid',
                             compartment='c'),
            '5m2h':
            cobra.Metabolite('5m2hcoa__E_c',
                             formula='X',
                             name='5-methyl-trans-hex-2-enoyl-ACP',
                             compartment='c'),
            '5m3o':
            cobra.Metabolite('5mhcoa_c',
                             formula='X',
                             name='5-Methyl-3-oxohexanoyl-ACP',
                             compartment='c'),
            'i2b2':
            cobra.Metabolite('i2b2_c',
                             formula='C8H12O4',
                             name='(2E)-2-Isobutyl-2-butenedioic acid',
                             compartment='c'),
            'leupyrrin_1':
            cobra.Metabolite('leupyrrin_1_c',
                             formula='X',
                             name='leupyrrin intermediate',
                             compartment='c')
        }


        self.cofactor_reactions_dict = {  # reactions that are specific to certain domains
            'PKS_KR': {self.cofactor_metabolites_dict['nadph']: -1.0, self.cofactor_metabolites_dict['h+']: -1.0,
                       self.cofactor_metabolites_dict['nadp']: 1.0},
            'cMT': {self.cofactor_metabolites_dict['sam']: -1.0, self.cofactor_metabolites_dict['sah']: 1.0},
            'oMT': {self.cofactor_metabolites_dict['sam']: -1.0, self.cofactor_metabolites_dict['sah']: 1.0},
            'PKS_DH': {self.cofactor_metabolites_dict['h2o']: 1.0},
            'PKS_ER': {self.cofactor_metabolites_dict['nadph']: -1.0, self.cofactor_metabolites_dict['h+']: -1.0,
                       self.cofactor_metabolites_dict['nadp']: 1.0},
            'PKS_TE': {self.cofactor_metabolites_dict['h2o']: -1.0},
            'TD': {self.cofactor_metabolites_dict['nadph']: -1.0, self.cofactor_metabolites_dict['h+']: -1.0,
                       self.cofactor_metabolites_dict['nadp']: 1.0},
            'PKS_AT': {self.cofactor_metabolites_dict['coa']: 1.0, self.cofactor_metabolites_dict['co2']: 1.0},
            'Condensation': {self.cofactor_metabolites_dict['h2o']: -1.0},
            'nMT': {self.cofactor_metabolites_dict['sam']: -1.0, self.cofactor_metabolites_dict['sah']: 1.0},
            'mxmal': {
                      self.cofactor_metabolites_dict['mxacp']: -1.0,
                      self.model.metabolites.get_by_id('13dpg_c'): -1.0,
                      self.model.metabolites.get_by_id('pi_c'): 2.0,
                      self.model.metabolites.get_by_id('nad_c'): -1.0,
                      self.model.metabolites.get_by_id('nadh_c'): 1.0,
                      self.model.metabolites.get_by_id('h_c'): 1.0,
                      self.model.metabolites.get_by_id('amet_c'): -1.0,
                      self.model.metabolites.get_by_id('ahcys_c'): 1.0,
                      self.model.metabolites.get_by_id('fad_c'): -1.0,
                      self.model.metabolites.get_by_id('fadh2_c'): 1.0,
                      self.cofactor_metabolites_dict['mxmal']: 1.0},


            'hpg_1': {self.model.metabolites.get_by_id('pphn_c'): -1,
                      self.model.metabolites.get_by_id('34hpp_c'): 1,
                      self.model.metabolites.get_by_id('co2_c'): 1,
                      self.model.metabolites.get_by_id('h2o_c'): 1},

            'hpg_2': {self.model.metabolites.get_by_id('34hpp_c'): -1,
                      self.model.metabolites.get_by_id('o2_c'): -1,
                      self.model.metabolites.get_by_id('h2o_c'): 1,
                      self.model.metabolites.get_by_id('4hmda_c'): 1},

            'hpg_3': {self.model.metabolites.get_by_id('4hmda_c'): -1,
                      self.model.metabolites.get_by_id('fmn_c'): -1,
                      self.model.metabolites.get_by_id('fmnh2_c'): 1,
                      self.model.metabolites.get_by_id('nadh_c'): -1,
                      self.model.metabolites.get_by_id('nad_c'): 1,
                      self.cofactor_metabolites_dict['4hbf']: 1},

            'hpg_4': {self.cofactor_metabolites_dict['4hbf']: -1,
                      self.model.metabolites.get_by_id('tyr__L_c'): -1,
                      self.model.metabolites.get_by_id('34hpp_c'): 1,
                      self.cofactor_metabolites_dict['hpg']: 1},

            'bht': {self.model.metabolites.get_by_id('tyr__L_c'): -1,
                    self.model.metabolites.get_by_id('o2_c'): -1,
                    self.model.metabolites.get_by_id('nadph_c'): -1,
                    self.model.metabolites.get_by_id('h_c'): -1,
                    self.model.metabolites.get_by_id('nadp_c'): 1,
                    self.cofactor_metabolites_dict['hpg']: 1},

            'dpg': {self.model.metabolites.get_by_id('accoa_c'): -1,
                    self.model.metabolites.get_by_id('malcoa_c'): -3,
                    self.model.metabolites.get_by_id('coa_c'): 4,
                    self.model.metabolites.get_by_id('co2_c'): 3,
                    self.model.metabolites.get_by_id('h2o_c'): 1,
                    self.model.metabolites.get_by_id('tyr__L_c'): -1,
                    self.model.metabolites.get_by_id('34hpp_c'): 1,
                    self.cofactor_metabolites_dict['dpg']: 1},

            'gnat': {self.model.metabolites.get_by_id('malcoa_c'): -1,
                     self.model.metabolites.get_by_id('co2_c'): 1,
                     self.model.metabolites.get_by_id('coa_c'): 1},

            'fkbh': {self.model.metabolites.get_by_id('13dpg_c'): -1.0,
                     self.model.metabolites.get_by_id('pi_c'): 2.0},

            # See https://www.genome.jp/kegg-bin/show_pathway?rn01051 and
            # https://biocyc.org/META/NEW-IMAGE?type=PATHWAY&object=PWY-5979
            'ahba-synthesis': {self.model.metabolites.get_by_id('udpg_c'):-1,
                     self.model.metabolites.get_by_id('nad_c'): -1,
                     self.model.metabolites.get_by_id('nadh_c'): 1,
                     self.model.metabolites.get_by_id('h_c'): 3,
                     self.model.metabolites.get_by_id('gln__L_c'): -1,
                     self.model.metabolites.get_by_id('HC00591_c'): 1,
                     self.model.metabolites.get_by_id('udp_c'): 1,
                     self.model.metabolites.get_by_id('atp_c'): -1,
                     self.model.metabolites.get_by_id('adp_c'): 1,
                     self.model.metabolites.get_by_id('r5p_c'): -1,
                     self.model.metabolites.get_by_id('s7p_c') : 1,
                     self.model.metabolites.get_by_id('pep_c'): -1,
                     self.model.metabolites.get_by_id('pi_c'): 2,
                     self.cofactor_metabolites_dict["ahba"]: 1},

            'ahba': {self.cofactor_metabolites_dict["ahba"]: -1,
                     self.model.metabolites.get_by_id('atp_c'): -1,
                     self.model.metabolites.get_by_id('amp_c'):  1,
                     self.model.metabolites.get_by_id('ppi_c'):  1,
                     self.model.metabolites.get_by_id('h2o_c'):  1},

            'acetyl': {self.model.metabolites.get_by_id('accoa_c'): -1,
                       self.model.metabolites.get_by_id('coa_c'): 1,
                       self.model.metabolites.get_by_id('co2_c'): 1},

            'shikimic_acid': {self.model.metabolites.get_by_id('skm_c'): -1,
                              self.model.metabolites.get_by_id('atp_c'): -1,
                              self.model.metabolites.get_by_id('amp_c'):  1,
                              self.model.metabolites.get_by_id('ppi_c'):  1,
                              self.model.metabolites.get_by_id('h2o_c'):  1},

            'fatty_acid': {self.model.metabolites.get_by_id('accoa_c'): -1,
                           self.model.metabolites.get_by_id('malcoa_c'): -3,
                           self.model.metabolites.get_by_id('co2_c'): 4,
                           self.model.metabolites.get_by_id('coa_c'): 4},

            'NH2': {self.model.metabolites.get_by_id('malcoa_c'): -1,
                    self.model.metabolites.get_by_id('co2_c'): 2,
                    self.model.metabolites.get_by_id('gly_c'): -1,
                    self.model.metabolites.get_by_id('coa_c'): 1
                    },

            # https://www.sciencedirect.com/topics/immunology-and-microbiology/ascomycin
            'pip': {self.model.metabolites.get_by_id('pyr_c'): -1,
                    self.model.metabolites.get_by_id('lys__L_c'): -1,
                    self.model.metabolites.get_by_id('h2o_c'): 1,
                    self.model.metabolites.get_by_id('nadph_c'): -1,
                    self.model.metabolites.get_by_id('nadp_c'): 1,
                    self.model.metabolites.get_by_id('h_c'): -1,
                    self.cofactor_metabolites_dict['pip']: 1},

            'NRPS_acylating_loader': {self.cofactor_metabolites_dict["fatty_acid_X"]: -1,
                                      self.model.metabolites.get_by_id("coa_c"): 1},
            # R10992 in KEGG, could also be R10991
            'abu': {self.model.metabolites.get_by_id('2obut_c'): -1,
                    self.model.metabolites.get_by_id('ala__L_c'): -1,
                    self.model.metabolites.get_by_id('pyr_c'): 1,
                    self.cofactor_metabolites_dict["abu"]: 1},
        }

        # beta_hydroxy_acids = {
        #     '3hpp':  self.model.metabolites.get_by_id("3hpp_c"),
        #     'bhb': self.model.metabolites.get_by_id("bhb_c"),
        # }
        self.fatty_acyl_CoAs = {
            "3hpcoa": self.model.metabolites.get_by_id("3hpcoa_c"),
            # "ptpcoa": self.model.metabolites.get_by_id("ptpcoa_c"),
            "hxcoa": self.model.metabolites.get_by_id("hxcoa_c"),
            # "hepcoa":  self.model.metabolites.get_by_id("hepcoa_c"),
            "occoa": self.model.metabolites.get_by_id("occoa_c"),
            "dcacoa": self.model.metabolites.get_by_id("dcacoa_c")
        }

        # self.condensation_initiation_cofactors = {
        #     self.model.metabolites.get_by_id('h2o_c'): 1
        # }

        self.tailoring_metabolites_dict = {
            'glucose_6_phosphate': self.model.metabolites.get_by_id('g6p_c'),
            '13biphosphoglycerate':
            self.model.metabolites.get_by_id('13dpg_c'),
            'succinyl_coa': self.model.metabolites.get_by_id('succoa_c'),
            'glycine': self.model.metabolites.get_by_id('gly_c'),
            'coa': self.model.metabolites.get_by_id('coa_c'),
            'co2': self.model.metabolites.get_by_id('co2_c'),
            'atp': self.model.metabolites.get_by_id('atp_c'),
            'amp': self.model.metabolites.get_by_id('amp_c'),
            'ppi': self.model.metabolites.get_by_id('ppi_c'),
            'pi': self.model.metabolites.get_by_id('pi_c'),
            'nadh': self.model.metabolites.get_by_id('nadph_c'),
            'nad': self.model.metabolites.get_by_id('nadp_c'),
            'h+': self.model.metabolites.get_by_id('h_c'),
            'h2o': self.model.metabolites.get_by_id('h2o_c')
        }

        self.tailoring_reactions_dict = {  # remember to add the secondary metabolite to these reactions
            'glycosyltransferase': {
                self.tailoring_metabolites_dict['glucose_6_phosphate']: -1,
                self.tailoring_metabolites_dict['h+']: 1,
                self.tailoring_metabolites_dict['pi']: 1
            },
            'glycerol': {
                self.tailoring_metabolites_dict['13biphosphoglycerate']: -1.0,
                self.tailoring_metabolites_dict['pi']: 2.0,
                self.tailoring_metabolites_dict['h+']: -1.0,
                self.tailoring_metabolites_dict['nad']: 1.0,
                self.tailoring_metabolites_dict['nadh']: -1.0,
            },
            'ALA': {
                self.tailoring_metabolites_dict['succinyl_coa']: -1.0,
                self.tailoring_metabolites_dict['glycine']: -1.0,
                self.tailoring_metabolites_dict['atp']: -1.0,
                self.tailoring_metabolites_dict['ppi']: 1.0,
                self.tailoring_metabolites_dict['co2']: 1.0,
                self.tailoring_metabolites_dict['coa']: 1.0,
                self.tailoring_metabolites_dict['amp']: 1.0,
                self.tailoring_metabolites_dict['h2o']: 1.0
            }
        }
Example #21
0
def no_compartments(base):
    """
    Provide a model with no compartments.
    """
    base.add_metabolites([cobra.Metabolite('MNXM161')])
    return base
Example #22
0
def test_design_parent():
    """ Design class should throw errors for cyclical parent designs, but accept valid hierarchy"""
    with FakeProjectContext() as ctx:
        project = GSMProject(ctx.path)
        # Create a design
        model = project.load_model()
        # Phosphoribulokinase reaction
        stoich = dict(
            atp_c=-1.0,
            ru5p__D_c=-1.0,
            adp_c=1.0,
            h_c=1.0,
            rb15bp_c=1.0,
        )

        rb15bp = cobra.Metabolite(id='rb15bp_c',
                                  name='D-Ribulose 1,5-bisphosphate',
                                  formula='C5H8O11P2',
                                  charge=0)
        model.add_metabolites(rb15bp)

        pruk = cobra.Reaction(id="PRUK",
                              name="Phosphoribulokinase reaction",
                              lower_bound=-1000,
                              upper_bound=1000)
        model.add_reactions([pruk])
        pruk.add_metabolites(stoich)

        # Rubisco reaction (Ribulose-bisphosphate carboxylase)
        stoich = {
            "3pg_c": 2.0,
            "rb15bp_c": -1.0,
            "co2_c": -1.0,
            "h2o_c": -1.0,
            "h_c": 2.0
        }

        rubisco = cobra.Reaction(id="RBPC",
                                 lower_bound=0,
                                 upper_bound=1000.0,
                                 name="Ribulose-bisphosphate carboxylase")

        model.add_reactions([rubisco])
        rubisco.add_metabolites(stoich)

        model.genes.get_by_id("b3916").knock_out()
        model.genes.get_by_id("b1723").knock_out()
        model.genes.get_by_id("b1852").knock_out()

        model.reactions.EX_glc__D_e.lower_bound = -10.0
        model.reactions.EX_nh4_e.lower_bound = -1000.0

        design = project.save_design(
            model,
            'cbb_cycle',
            'calvin cycle',
            description='Reactions necissary for the calvin cycle in ecoli',
            overwrite=True)
        # Test html string
        # Test string representation
        str(design)
        design._repr_html_()

        # test jsonschema is valid
        design.validate_dict(design.to_dict())

        # Create a child of this design
        model = project.load_design('cbb_cycle')
        reaction = cobra.Reaction(id="HMGCOASi",
                                  name="Hydroxymethylglutaryl CoA synthase")

        aacoa = cobra.Metabolite(id="aacoa_c",
                                 charge=-4,
                                 formula="C25H36N7O18P3S",
                                 name="Acetoacetyl-CoA")
        hmgcoa = cobra.Metabolite(id="hmgcoa_c",
                                  charge=-5,
                                  formula="C27H40N7O20P3S",
                                  name="Hydroxymethylglutaryl CoA")

        model.add_metabolites([aacoa, hmgcoa])

        stoich = dict(
            aacoa_c=-1.0,
            accoa_c=-1.0,
            coa_c=1.0,
            h_c=1.0,
            h2o_c=-1.0,
            hmgcoa_c=1.0,
        )

        model.add_reactions([reaction])
        reaction.add_metabolites(stoich)
        reaction.lower_bound = -1000.0
        reaction.upper_bound = 1000.0

        mev__R = cobra.Metabolite(id="mev__R_c",
                                  name="R Mevalonate",
                                  charge=-1,
                                  formula="C6H11O4")
        model.add_metabolites([mev__R])

        reaction = cobra.Reaction(id="HMGCOAR",
                                  name="Hydroxymethylglutaryl CoA reductase")
        reaction.lower_bound = -1000.0
        reaction.upper_bound = 1000.0

        stoich = dict(coa_c=-1.0,
                      h_c=2.0,
                      nadp_c=-2.0,
                      nadph_c=2.0,
                      hmgcoa_c=1.0,
                      mev__R_c=-1.0)

        model.add_reactions([reaction])

        reaction.add_metabolites(stoich)

        model.add_boundary(mev__R,
                           type='sink')  # add somewhere for mevalonate to go

        design = project.save_design(
            model,
            'mevalonate_cbb',
            'mevalonate production',
            parent='cbb_cycle',
            description='Reactions for the production of mevalonate',
            overwrite=True)

        des = project.get_design('mevalonate_cbb')

        inf = des.info
        pmodel = des.as_pathway_model()
        # TODO Test reactions are correct (counts should be correct)
        des.reactions_dataframe()
        des.genes_dataframe()
        des.to_dict()
        des.metabolites_dataframe()
        des.removed_genes

        # Check copying models works
        tmodel = cobra.Model()
        tmodel.id = 'test'
        des.add_to_model(tmodel, copy=True)
        # Requires a cobra model
        with pytest.raises(TypeError):
            des.add_to_model(model=None)

        # try to overwrite
        with pytest.raises(IOError):
            path = os.path.join(project._project_path,
                                project.config.design_dir,
                                '{}.json'.format(des.id))
            des.to_json(path, overwrite=False)

        # Try to save a design with a bad parent
        with pytest.raises(DesignError):
            des.id = 'fuuuu'
            project.save_design(
                model,
                'mevalonate_cbbd',
                'mevalonate production',
                parent=des,
                description='Reactions for the production of mevalonate')

        _ = project.list_models
        _ = project.list_conditions
Example #23
0
					try:
						coeff = int(coeff_and_name[0])
						met_name = ' '.join(coeff_and_name[1:])
					except:
						coeff = 1
						met_name = row[col]
					met_id = met_id_row[col]
					if met_id.endswith('_e0'):
						comp = 'e0'
					else:
						comp = 'c0'
						met_id = met_id + '_c0'
					if met_id in FBA_model.metabolites:
						met = FBA_model.metabolites.get_by_id(met_id)
					else:
						met = cobra.Metabolite(met_id, name=met_name, compartment=comp)
					if leftside:
						left_dict[met] = -1*coeff
					else:
						right_dict[met] = dir_coeff*coeff
			if dir_coeff == -1:
				for key,val in left_dict.items():
					left_dict[key] = -1*val
			new_rxn = cobra.Reaction(rxn_id)
			FBA_model.add_reaction(new_rxn)
			new_rxn.add_metabolites(left_dict)
			new_rxn.add_metabolites(right_dict)
			print(new_rxn.build_reaction_string(use_metabolite_names = True))
		try:
			row = next(rxn_reader)
		except:
Example #24
0
def test_create_design():
    """
    Create a design that adds and removes reactions
    """
    with FakeProjectContext() as ctx:
        project = GSMProject(ctx.path)
        model = project.model
        # Growth on xylose instead of glucose
        model.reactions.EX_xyl__D_e.lower_bound = -8.00
        model.reactions.EX_glc__D_e.lower_bound = 0.0

        project.save_conditions(model, 'xylose_growth')

        model.reactions.ATPM.lower_bound = 8.0
        # Modified metabolite (all the water turned to hydrogen peroxide!?)
        model.metabolites.h2o_c.formula = 'H202'
        # Remove a reaction
        model.reactions.UDPGD.remove_from_model()

        # Add a reaction with a hetrologous metabolite
        metabolite = cobra.Metabolite()
        metabolite.id = 'test_c'
        metabolite.name = 'test_metabolite'
        metabolite.charge = 0
        metabolite.formula = ''
        metabolite.notes = {}
        metabolite.annotation = {}
        metabolite.compartment = 'c'

        model.add_metabolites([metabolite])

        reaction = cobra.Reaction()

        reaction.id = 'test_reaction'
        reaction.name = 'test'
        reaction.lower_bound = -1000.0
        reaction.upper_bound = 1000.0

        model.add_reactions([reaction])

        reaction.add_metabolites({
            'h2o_c': -1,
            'glx_c': -1,
            'test_c': 1,
            'o2_c': 1
        })

        model.add_boundary(metabolite, type='demand')

        # Add transporter for hetrologous metabolite
        project.save_design(model,
                            'test_design',
                            'test design 01',
                            'This is a test',
                            conditions='xylose_growth')

        # Can't save a design twice
        with pytest.raises(IOError):
            project.save_design(model,
                                'test_design',
                                'test design 01',
                                'This is a test',
                                conditions='xylose_growth')

        # Invalid base model
        with pytest.raises(KeyError):
            project.save_design(model,
                                'test_design22',
                                'test design 0221',
                                'This is a test',
                                base_model='NONE')

        del model

        # assert design has been saved
        assert 'test_design' in project.list_designs
        assert os.path.exists(
            os.path.join(ctx.path, 'designs', 'test_design.json'))

        # Test loading the design into the default model
        nmodel = project.load_design('test_design')

        nmodel.reactions.get_by_id('test_reaction')
        nmodel.metabolites.get_by_id('test_c')

        # assert that the reaction is removed
        with pytest.raises(KeyError):
            nmodel.reactions.get_by_id('UDPGD')

        # assert that the metabolite is changed
        assert nmodel.metabolites.h2o_c.formula == 'H202'

        # assert that the reaction bounds have been modified
        assert nmodel.reactions.ATPM.lower_bound == 8.0

        # check conditions are loaded
        assert nmodel.reactions.EX_xyl__D_e.lower_bound == -8.00
        assert nmodel.reactions.EX_glc__D_e.lower_bound == 0.0
Example #25
0
    def make_L1_prob(self, df):
        """
        Make L1-norm minimization problem to fit proteome to measured 
        mass fractions in provided dataframe.
        Useful as a first step in StressME reconstruction as it 
        identifies blocked proteins and reactions that would prevent
        simulation of certain stress responses
        """
        me0 = self.me
        # Make copy of me or not...?
        me = cp.deepcopy(me0)
        # Reset obj coeffs
        for rxn in me.reactions:
            rxn.objective_coefficient = 0.
        # Add variable and constrain it to total proteome mass
        cons_p = cobra.Metabolite('p_eq_proteome_mass')

        p = cobra.Reaction('proteome_mass')
        p.lower_bound = 0.
        p.upper_bound = 1000.
        p.objective_coefficient = 0.
        p.add_metabolites({cons_p: 1.})
        me.add_reactions([p])

        for rxn in me.reactions.query('translation'):
            rxn.add_metabolites({cons_p: -rxn.translation_data.mass})

        # Add constraint & aux var for each proteine mf to fit
        for ind, row in dfi.iterrows():
            # Add constraints
            cons_l1 = cobra.Metabolite('error_' + row.locus_tag + '_1')
            cons_l2 = cobra.Metabolite('error_' + row.locus_tag + '_2')

            # Add auxiliary var
            s = cobra.Reaction('s_' + row.locus_tag)
            s.lower_bound = 0.
            s.upper_bound = 1000.
            s.add_metabolites({cons_l1: -1., cons_l2: -1.})
            s.objective_coefficient = 1.

            # Add slack vars
            y1 = cobra.Reaction('y1_' + row.locus_tag)
            y1.lower_bound = 0.
            y1.upper_bound = 1000.
            y1.objective_coefficient = 0.
            y2 = cobra.Reaction('y2_' + row.locus_tag)
            y2.lower_bound = 0.
            y2.upper_bound = 1000.
            y2.objective_coefficient = 0.
            y1.add_metabolites({cons_l1: 1.})
            y2.add_metabolites({cons_l2: 1.})

            # Translation of i.
            rxn_trsli = me.reactions.get_by_id('translation_' + row.locus_tag)
            mfi = row.mf
            mwi = row.mw
            rxn_trsli.add_metabolites({cons_l1: mwi})
            rxn_trsli.add_metabolites({cons_l2: -mwi})

            # All proteins: can just use the p variable we made earlier
            p.add_metabolites({cons_l1: -mfi, cons_l2: mfi})

            # Add remaining new columns
            me.add_reactions([s, y1, y2])

        me_nlp_l1 = ME_NLP(me)
        self.me_nlp_l1 = me_nlp_l1
        print 'Finished making L1-norm problem: self.me_nlp_l1'

        return me_nlp_l1
Example #26
0
def load_scrumpy_model(filepath_or_string,
                       name=None,
                       model_id=None,
                       media=None,
                       objective_reactions=None,
                       obj_dir='min',
                       fixed_fluxes=None):
    """
    Specify a base scrumpy structural model file and returns a cobra model.
    This hasn't be thoroughly tested so expect there to be bugs

    To get a solution from the returned object you need to specify nice stuff like the atpase reaction and media

    :param filepath_or_string: filepath or scrumpy string
    :param name:
    :param model_id:
    :param media:
    :param objective_reactions:
    :param obj_dir:
    :param fixed_fluxes:
    :return:
    """

    if objective_reactions is None:
        objective_reactions = ['Biomass']

    if fixed_fluxes is not None:
        assert isinstance(fixed_fluxes, dict)

    if os.path.isfile(filepath_or_string):
        rel_path = '/'.join(
            os.path.abspath(filepath_or_string).split('/')[:-1])
        fp = os.path.abspath(filepath_or_string).split('/')[-1]
        reactions, metabolites, externals = parse_file(fp, rel_path=rel_path)
    else:
        rel_path = '.'
        reactions, metabolites, externals = parse_string(filepath_or_string,
                                                         rel_path=rel_path)

    model = cobra.Model()
    for mid in metabolites:
        compartment = 'e'
        if mid[:2] == "x_" or mid in externals:
            compartment = 'e'
        m = cobra.Metabolite(
            id=mid,
            compartment=compartment)  # ScrumPy does not use compartments
        model.add_metabolites([m])

    added_reactions = []
    for reaction in reactions:
        if reaction['id'] not in added_reactions:
            r = cobra.Reaction(reaction['id'])
            model.add_reactions([r])
            r.lower_bound = reaction['bounds'][0]
            r.upper_bound = reaction['bounds'][1]
            r.add_metabolites(reaction['metabolites'])
            added_reactions.append(reaction['id'])

    # We need to add transporters for external metabolites not defined with the "External" directive
    for metabolite in model.metabolites:
        if metabolite.id[:2] == "x_":
            r = cobra.Reaction("EX_{}".format(metabolite.id[2:]))
            model.add_reactions([r])
            r.lower_bound = -1000.0
            r.upper_bound = 1000.0
            r.add_metabolites({metabolite.id: -1.0})
            added_reactions.append(r.id)

    if media is not None:
        for ex_reaction in model.exchanges:
            ex_reaction.lower_bound = media.get(ex_reaction.id, 0)

    if fixed_fluxes is not None:
        for rid, flux in fixed_fluxes.items():
            try:
                reaction = model.reactions.get_by_id(rid)
                reaction.lower_bound = flux
                reaction.upper_bound = flux
            except KeyError:
                click.echo(
                    'Error setting fixed flux for reaction id {}, not found'.
                    format(rid))

    for oreact in objective_reactions:
        try:
            objreac = model.reactions.get_by_id(oreact)
            objreac.objective_coefficient = 1.0
        except KeyError:
            print('Error setting objective, reaction name {} not found'.format(
                oreact))

    model.objective.direction = obj_dir

    model.id = model_id
    model.name = name
    return model
Example #27
0
def sum_outside_of_deviation(base):
    """ Same as above, yet here H2O is on the wrong side of the equation
    which will throw off the balance.
    """
    met_a = cobra.Metabolite("lipid_c", "H744")
    met_b = cobra.Metabolite("protein_c", "H119")
    met_c = cobra.Metabolite("rna_c", "H496")
    met_d = cobra.Metabolite("dna_c", "H483")
    met_e = cobra.Metabolite("ash_c", "H80")
    met_f = cobra.Metabolite("cellwall_c", "H177")
    met_g = cobra.Metabolite("atp_c", "C10H12N5O13P3")
    met_h = cobra.Metabolite("adp_c", "C10H12N5O10P2")
    met_i = cobra.Metabolite("h_c", "H")
    met_j = cobra.Metabolite("h2o_c", "H2O")
    met_k = cobra.Metabolite("pi_c", "HO4P")
    # Reactions
    rxn_1 = cobra.Reaction("BIOMASS_TEST")
    rxn_1.add_metabolites({met_a: -0.133, met_b: -5.834, met_c: -0.1,
                           met_d: -0.0625, met_e: -0.875, met_f: -0.2778,
                           met_g: -30.0, met_h: 30.0, met_i: 30.0,
                           met_j: 30.0, met_k: 30.0
                           })
    base.add_reactions([rxn_1])
    return base
Example #28
0
def calculate_minspan_column(model_pickle, original_fluxes, column_index, N,
                             cores, timelimit, verbose, solver_name):
    """calculate a single minspan column

    This function minimizes the number of nonzero elements in the column
    given by column_index while ensuring it remains a feasible vector and
    linearly independent of all other columns.
    """
    solver = cobra.solvers.solver_dict[solver_name]
    n = N.shape[0]
    fluxes = original_fluxes.copy()

    # extract the old column and set it to 0
    oldPath = fluxes[:, column_index].copy()  # the old columm
    binOldPath = (oldPath != 0) * 1  # binary version
    fluxes[:, column_index] = 0  # set the column to 0

    # calculate N2, which the new vector must not be orthogonal to
    a = N.T * fluxes
    # a = matrix(numpy.linalg.lstsq(N, matrix(fluxes))[0])
    N2 = (N * matrix(null(a.T)))

    # ensure that the current solution is still feasible
    k = abs(oldPath * N2)[0, 0]
    # The MILP requires abs(N2 * x) >= 1. If k < 1, we can satisfy this
    # constraint by setting using x / k. However, we must ensure that by
    # scaling x we are not violating the lower or upper bounds. If we do, then
    # we must scale N2
    if k < 1:
        if abs(oldPath).max() / k > default_bound:
            N2 *= 1.0 / k
            print "N2 scaled"
        else:
            oldPath *= 1.0 / k

    # construct the MILP problem
    problem = loads(model_pickle)  # already has binary indicators
    # create constraint that N2 * fluxes != 0
    # This will be done by specifying that abs(N2 * fluxes) > 1
    fi_plus = cobra.Reaction("fi_plus")  # boolean for N2 * fluxes > 1
    fi_minus = cobra.Reaction("fi_minus")  # boolean for N2 * fluxes < -1
    make_binary(fi_plus)
    make_binary(fi_minus)
    fi_plus_constraint = cobra.Metabolite(id="fi_plus_constraint")
    fi_minus_constraint = cobra.Metabolite(id="fi_minus_constraint")
    fi_plus_constraint._constraint_sense = "G"
    fi_plus_constraint._bound = -1000
    fi_minus_constraint._constraint_sense = "G"
    fi_minus_constraint._bound = -1000
    fi_plus.add_metabolites({fi_plus_constraint: -1001})
    fi_minus.add_metabolites({fi_minus_constraint: -1001})
    problem.add_reactions([fi_plus, fi_minus])
    for i, N2_val in enumerate(N2.T.tolist()[0]):
        problem.reactions[i].add_metabolites({
            fi_plus_constraint: N2_val,
            fi_minus_constraint: -1 * N2_val
        })
    # constrain either fi+ or fi- must be true
    or_constraint = cobra.Metabolite(id="or_constraint")
    or_constraint._bound = 1
    or_constraint._constraint_sense = "G"
    fi_plus.add_metabolites({or_constraint: 1})
    fi_minus.add_metabolites({or_constraint: 1})
    # problem.update()
    # create the solver object
    lp = solver.create_problem(problem, objective_sense="minimize")
    # seed the variables with the old solution, and set extra arguments
    if solver_name.startswith("gurobi"):
        for i, variable in enumerate(lp.getVars()):
            if i < n:
                variable.Start = float(oldPath[i])
            elif i < 2 * n:
                variable.Start = float(binOldPath[i - n])
        solver.set_parameter(lp, "Method", 2)
        solver.set_parameter(lp, "Presolve", 2)
    elif solver_name.startswith("cplex"):
        # only seed cplex with the integer values
        # effort_level.solve_fixed tells cplex to solve the problem with these
        # values set, and then use that as an initial point for the entire
        # problem
        lp.MIP_starts.add((range(n, 2 * n), binOldPath.tolist()),
                          lp.MIP_starts.effort_level.repair)
    # solve the model with the new parameters
    status = solver.solve_problem(lp,
                                  verbose=verbose,
                                  threads=cores,
                                  time_limit=timelimit,
                                  MIP_gap=0.001,
                                  MIP_gap_abs=0.999)
    solution = solver.format_solution(lp, problem)
    # extract the solution
    if solution.status in acceptable_status:
        bin_flux = array(solution.x[n:2 * n])
        flux = array(solution.x[:n])
        flux[bin_flux < 1e-3] = 0  # round down
    else:
        print solution.status
        if solver_name.startswith("cplex"):
            status = lp.solution.get_status_string()
        elif solver_name.startswith("gurobi"):
            status = lp.status
        raise Exception("Solver failed with status %s" % status)
    return flux
Example #29
0
def create_community_model_with_balanced_growth(
    community: Community,
    growth_rate: float,
    organism_exchange_bounds: Dict[str, Tuple[float,
                                              float]] = {}) -> cobra.Model:
    """Creates a combined community model with an stoichiometric-matrix-integrated balanced growth approach.

    Description
    ----------
    *Aim of this function*

    This method is aimed to generate a community model (as described in the community argument of
    this function) with a fixed growth rate, where this growth rate is the same for each of the community's
    species, in a way in which this growth rate constraint is directly integrated into the community model
    itself so that this model can be used e.g. with common Flux Balace Analysis methods and funtions.

    *Basic background behind this function*

    In community models, both the fraction of single species on the total community
    biomass as well as the growth rate of each single species can be optimized, which would lead to a computaionally
    quite complex bilinear optimization. Since balanced growth (i.e., no species grows faster or slower than other species
    so that no species is outcompeted in the long term) requires a fixed growth rate, only the optimization of the species
    fractions remains and, therefore, a computationally much more efficient linear optimiztaion.

    As described e.g. in (Koch et al., 2019), the resulting minimal flux of an irreversible reaction j in species i with a minimal flux greater than 0
    is min_flux_j*f_i where f is the species's fraction, and, consequently, the resulting maximal flux (if the maximum is smalelr than inf) is max_flux_j*f_i. Usually,
    a special Flux Balance Analysis function introducing the fraction variables as added variables has to be written in order
    to run FBA with balanced growth.

    This unconvenient introduction of extra fraction variables can be ommitted by looking at the meaning of a species's fraction:
    Since the fractions of single species (if we give them the index i) f_i = µ_i/µ_community, where µ is the growth rate,
    and µ_community is fixed the only thing one to look at is µ_i, i.e. the "biomass contribution" of each species which
    is equal to their fraction.

    Hence, the simplified approach used heirin, which implicitly integrates the fraction variables into the stoichiometric
    matrix, is as follows:

    * For reactions with a minimal flux > 0: A new pseudo-metabolite is integrated as where it is produced by the reactions itself with the stoichiometry 1,
      and this metabolite is consumed by the reaction's species biomass reaction with the stoichiometry min_flux/fixed_growth_rate. Additionally, a
      pseudo-reaction consuming the pseudo-metabolite is added, too.
    * For reactions with a maximal flux < inf: A new pseudo-metabolite is integrated as where it is produced by the reactions itself with the stoichiometry 1,
      and this metabolite is consumed by the reaction's species biomass reaction with the stoichiometry max_flux/fixed_growth_rate. Additionally, a
      pseudo-reaction producing the pseudo-metabolite is added, too.


    *Principle of balanced growth constraint integration used herein*

    1. All metabolites and reactions of the single species (as defined in the SingleModel instances of the given Community instance)
       are renamed with the addition of "_"+species_abbreviation (species_abbreviation as defined in the SingleModel instance) at
       the end of their IDs.
    2. A new pseudo-metabolite called "COMMUNITY_BIOMASS" is added as product with stoichiometry 1 to all biomass reactions
       of the single species.
    3. All single species biomass reactions get the lower flux bound of 0 and upper flux bound of infinite.
    4. A new pseudo-reaction called "COMMUNITY_BIOMASS" is generated which has the upper and lower (i.e., fixed) flux equal
       to the given growth rate. This pseudo-reaction has the pseudo-metabolite "COMMUNITY_BIOMASS" as educt with a
       stoichiometry of 1.
    5. The pseudo-reactions (called "Rsnake_UPPER_" for maximal flux bounds and "Rsnake_LOWER_" for minimal flux bounds)
       and pseudo-metabolites (called "Msnake_UPPER_" for maximal flux bounds and "Msnake_LOWER_" for minimal flux bounds)
       are introduced into the model as described in the previous section.
    6. Exchange reactions between the single species comparments and the exchange compartment for all input/output
       metabolites from the respective SingleSpecies instances, as well as from the exchange
       compartment to the environment for all input/output metabolites of the Community instance. All previous standard
       exchanges of the single models (usually starting with "EX_") are deleted.
       The new exchange reactions start with EXCHG_in_ for input reactions (input to organism) and EXCHG_out_ for output metabolites
       (output from organism). Both types of EXCHG_ reactions are irreversible, and EXCHG_in_ reactions get an upper bound of
       1000 mmol/(gDW*h) as standard in order to enforce the incorporation of Msnake_UPPER_ upper bound metabolites so that growth is
       actually enforced for all organisms in which reactions occur (which may not be the case if reactions with lower/upper bounds
       of inf are used).

    The principle used herein also means that if another growth rate is to be tested, a new model has to be generated for this
    specific growth rate.

    Return value
    ----------
    A community model in the form of a cobrapy
    Model instance. This form of the community model - with its fixed organism
    ratios - can be e.g. used with the ASTHERISC package.

    Arguments
    ----------
    * community: Community ~ A CommModelPy Community instance.
    * growth_rate: float ~ The growth rate to which the community shall be fixed.
    * organism_exchange_bounds: Dict[Tuple[float, float]] ~ A dictionary containing reaction IDs
      (which may also include the EXCHG_ reactions introduced by this function) as keys
      and, in the float tuple at index 0 a set lower bound and at index 1 a set upper bound.
    """
    # Get number of SingleModel instances in Community instance
    num_single_models = len(community.single_models)
    # Check that an actual community is given
    if num_single_models <= 1:
        raise ValueError(
            "ERROR: Less than 2 models in given Community instance!")

    # Dictionary for later biomass introduction
    organism_id_biomass_reaction_id_mapping: Dict[str, str] = {}

    # Go through each SingleModel and change their cobra models
    for single_model in community.single_models:
        # Check that no underscores are in the organism IDs
        if "_" in single_model.species_abbreviation:
            raise ValueError(
                f"ERROR: Underscore in the given species abbreviation {single_model.species_abbreviation} D:"
            )

        # Rename metabolites
        for metabolite in single_model.cobra_model.metabolites:
            metabolite.id += "_" + single_model.species_abbreviation

        # Rename reactions and change bounds
        for reaction in single_model.cobra_model.reactions:
            reaction.id += "_" + single_model.species_abbreviation

        # Delete standard exchange reactions with default exchange reaction ID prefix
        standard_exchanges = [
            x for x in single_model.cobra_model.reactions
            if x.id.startswith(single_model.exchange_reaction_id_prefix)
        ]
        single_model.cobra_model.remove_reactions(standard_exchanges)

        # Add biomass reaction to dictionary
        organism_id_biomass_reaction_id_mapping[single_model.species_abbreviation] = single_model.objective_reaction_id + \
            "_" + single_model.species_abbreviation
        # Standardize single-organism biomass reaction bounds
        biomass_reaction = single_model.cobra_model.reactions.get_by_id(
            organism_id_biomass_reaction_id_mapping[
                single_model.species_abbreviation])
        biomass_reaction.lower_bound = 0
        biomass_reaction.upper_bound = float("inf")

    # Merge single models into a huge one
    merged_model = copy.deepcopy(community.single_models[0].cobra_model)
    for single_model in community.single_models[1:]:
        merged_model.merge(single_model.cobra_model, inplace=True)

    # Add community biomass metabolite
    community_biomass_metabolite = cobra.Metabolite(
        id="COMMUNITY_BIOMASS",
        name="Community biomass metabolite",
        compartment="exchg")
    merged_model.add_metabolites([community_biomass_metabolite])
    for biomass_reaction_id in organism_id_biomass_reaction_id_mapping.values(
    ):
        biomass_reaction = merged_model.reactions.get_by_id(
            biomass_reaction_id)
        biomass_reaction.add_metabolites({
            community_biomass_metabolite: 1,
        })

    # Add whole community exchanges
    exchange_metabolite_ids = list(
        set(community.input_metabolite_ids + community.output_metabolite_ids))
    for exchange_metabolite_id in exchange_metabolite_ids:
        # Set reaction instance
        reaction = cobra.Reaction(
            id=community.exchange_reaction_id_prefix + exchange_metabolite_id +
            "_" + community.exchange_compartment_id,
            name="Community exchange for " + exchange_metabolite_id)

        # Set reaction bounds
        is_input = exchange_metabolite_id in community.input_metabolite_ids
        if is_input:
            reaction.lower_bound = -float("inf")
        else:
            reaction.lower_bound = 0
        is_output = exchange_metabolite_id in community.output_metabolite_ids
        if is_output:
            reaction.upper_bound = float("inf")
        else:
            reaction.upper_bound = 0

        # Add metabolite to reaction
        exchange_metabolite = cobra.Metabolite(
            exchange_metabolite_id + "_" + community.exchange_compartment_id,
            name="Exchange compartment metabolite " + exchange_metabolite_id,
            compartment="exchange")
        reaction.add_metabolites({
            exchange_metabolite: -1,
        })

        # Add reaction to model
        merged_model.add_reactions([reaction])

    # Split reversible reactions
    merged_model = split_reversible_organism_reactions(
        merged_model, organism_id_biomass_reaction_id_mapping)

    # Add community biomass reaction and set it to the given growth rate
    community_biomass_reaction = cobra.Reaction(
        id="COMMUNITY_BIOMASS",
        name="Biomass reaction for the whole community")
    community_biomass_reaction.lower_bound = growth_rate
    community_biomass_reaction.upper_bound = growth_rate
    community_biomass_reaction.add_metabolites({
        community_biomass_metabolite:
        -1,
    })

    # Add single species <-> exchange compartment exchanges
    for single_model in community.single_models:
        exchange_metabolite_ids = list(
            set(single_model.input_metabolite_ids +
                single_model.output_metabolite_ids))
        exchange_metabolite_ids = [
            x + "_" + single_model.species_abbreviation
            for x in exchange_metabolite_ids
        ]

        for exchange_metabolite_id in exchange_metabolite_ids:
            single_model_base_metabolite_id = exchange_metabolite_id.replace(
                "_" + single_model.species_abbreviation, "")
            exchange_compartment_metabolite_id = single_model.model_metabolite_to_exchange_id_mapping[
                single_model_base_metabolite_id]

            # Add metabolites to reaction
            try:
                internal_metabolite = merged_model.metabolites.get_by_id(
                    exchange_metabolite_id)
            except:
                print("ERROR: Internal exchange metabolite ID " +
                      exchange_metabolite_id + "does not exist!")
            species_exchange_metabolite_id = exchange_compartment_metabolite_id + "_" + community.exchange_compartment_id
            try:
                exchange_compartment_metabolite = merged_model.metabolites.get_by_id(
                    species_exchange_metabolite_id)
            except:
                new_species_exchange_metabolite = cobra.Metabolite(
                    id=species_exchange_metabolite_id, compartment="exchg")
                merged_model.add_metabolites(new_species_exchange_metabolite)
                exchange_compartment_metabolite = merged_model.metabolites.get_by_id(
                    species_exchange_metabolite_id)

            # Set reaction bounds
            is_input = single_model_base_metabolite_id in single_model.input_metabolite_ids
            is_output = single_model_base_metabolite_id in single_model.output_metabolite_ids

            # Set reaction instance
            if is_input:
                reaction_in = cobra.Reaction(
                    id="EXCHG_in_" + single_model.species_abbreviation + "_" +
                    exchange_metabolite_id.replace(
                        "_" + single_model.species_abbreviation, "") + "_to_" +
                    exchange_compartment_metabolite_id,
                    name=
                    f"Input exchange for {exchange_metabolite_id} from single species {single_model.species_abbreviation} to exchange compartment"
                )
                reaction_in.add_metabolites({
                    exchange_compartment_metabolite: -1,
                    internal_metabolite: 1,
                })
                reaction_in.lower_bound = 0
                reaction_in.upper_bound = 1000

                merged_model.add_reactions([reaction_in])
            if is_output:
                reaction_out = cobra.Reaction(
                    id="EXCHG_out_" + single_model.species_abbreviation + "_" +
                    exchange_metabolite_id.replace(
                        "_" + single_model.species_abbreviation, "") + "_to_" +
                    exchange_compartment_metabolite_id,
                    name=
                    f"Output exchange for {exchange_metabolite_id} from single species {single_model.species_abbreviation} to exchange compartment"
                )
                reaction_out.add_metabolites({
                    internal_metabolite:
                    -1,
                    exchange_compartment_metabolite:
                    1,
                })
                reaction_out.lower_bound = 0
                reaction_out.upper_bound = float("inf")

                merged_model.add_reactions([reaction_out])

    # Add organism-specific reaction bounds
    bound_reaction_ids = [
        x.id for x in merged_model.reactions
        if x.id in list(organism_exchange_bounds.keys())
    ]
    for bound_reaction_id in bound_reaction_ids:
        lower_bound = organism_exchange_bounds[bound_reaction_id][0]
        upper_bound = organism_exchange_bounds[bound_reaction_id][1]
        reaction = merged_model.reactions.get_by_id(bound_reaction_id)
        reaction.lower_bound = lower_bound
        reaction.upper_bound = upper_bound

    # Add minimal and maximal bound constraints using pseudo-metabolites and pseudo-reactions
    reaction_ids = [x.id for x in merged_model.reactions]
    for reaction_id in reaction_ids:
        reaction = merged_model.reactions.get_by_id(reaction_id)

        # Check organism ID
        if reaction_id.startswith("EXCHG"):
            reaction_organism_id = reaction.id.split("_")[2]
            if reaction_organism_id not in organism_id_biomass_reaction_id_mapping.keys(
            ):
                continue
        else:
            reaction_organism_id = reaction.id.split("_")[-1]
            if reaction_organism_id not in organism_id_biomass_reaction_id_mapping.keys(
            ):
                continue

        organism_biomass_reaction = merged_model.reactions.get_by_id(
            organism_id_biomass_reaction_id_mapping[reaction_organism_id])
        # Add maximal bound constraint
        if reaction.upper_bound != float("inf"):
            # Add ~M
            new_metabolite = cobra.Metabolite(
                id="Msnake_UPPER_" + reaction.id,
                name="Upper bound enforcing metabolite for " + reaction.id,
                compartment="exchg")
            # Add ~r
            new_reaction = cobra.Reaction(
                id="Rsnake_UPPER_" + reaction.id,
                name=
                "Delivery reaction of upper bound enforcing metabolite for " +
                reaction.id)

            # Add ~M to original reaction
            reaction.add_metabolites({
                new_metabolite: 1,
            })
            organism_biomass_reaction.add_metabolites({
                new_metabolite:
                -reaction.upper_bound / growth_rate,
            })
            new_reaction.add_metabolites({
                new_metabolite: 1,
            })
            merged_model.add_reactions([new_reaction])

            reaction.upper_bound = float("inf")

        # Add minimal bound constraint
        if (reaction.lower_bound != -float("inf")) and (reaction.lower_bound !=
                                                        0.0):
            # Add ~M
            new_metabolite = cobra.Metabolite(
                id="Msnake_LOWER_" + reaction.id,
                name="Lower bound enforcing metabolite for " + reaction.id,
                compartment="exchg")
            # Add ~r
            new_reaction = cobra.Reaction(
                id="Rsnake_LOWER_" + reaction.id,
                name=
                "Consuming reaction of lower bound enforcing metabolite for " +
                reaction.id)

            # Add ~M to original reaction
            reaction.add_metabolites({
                new_metabolite: 1,
            })
            organism_biomass_reaction.add_metabolites({
                new_metabolite:
                -reaction.lower_bound / growth_rate,
            })
            new_reaction.add_metabolites({
                new_metabolite: -1,
            })
            merged_model.add_reactions([new_reaction])

            reaction.lower_bound = 0

    # Set merged model's objective to community biomass
    merged_model.add_reactions([community_biomass_reaction])
    merged_model.objective = "COMMUNITY_BIOMASS"

    return merged_model
Example #30
0
def three_present(base):
    base.add_metabolites([
        cobra.Metabolite(id="M{0:d}".format(i), formula="CH4", charge=-1)
        for i in range(1, 4)
    ])
    return base