10. Growth media

The availability of nutrients has a major impact on metabolic fluxes and cobrapy provides some helpers to manage the exchanges between the external environment and your metabolic model. In experimental settings the “environment” is usually constituted by the growth medium, ergo the concentrations of all metabolites and co-factors available to the modeled organism. However, constraint-based metabolic models only consider fluxes. Thus, you will first have to translate your concentrations into fluxes. For instance by assuming that 1 gDW of your organism cannot consume the entire concentration of a metabolite in 24h which gives you an estimate of the upper exchange flux of concentration / (1 gDW * 24 h). If you have direct measurement of exchange fluxes you can of course use those as well (and those will be much more accurate).

The current growth medium of a model is managed by the medium attribute.

In [1]:
from cobra.test import create_test_model

model = create_test_model("textbook")
model.medium
Out[1]:
{'EX_co2_e': 1000.0,
 'EX_glc__D_e': 10.0,
 'EX_h2o_e': 1000.0,
 'EX_h_e': 1000.0,
 'EX_nh4_e': 1000.0,
 'EX_o2_e': 1000.0,
 'EX_pi_e': 1000.0}

This will return a dictionary that contains all active exchange fluxes (the ones having non-zero flux bounds). Right now we see that we have enabled aerobic growth. You can modify a growth medium of a model by assigning a dictionary to model.medium that maps exchange reactions to their respective upper import bounds. For now let us enforce anaerobic growth by shutting off the oxygen import.

In [2]:
medium = model.medium
medium["EX_o2_e"] = 0.0
model.medium = medium

model.medium
Out[2]:
{'EX_co2_e': 1000.0,
 'EX_glc__D_e': 10.0,
 'EX_h2o_e': 1000.0,
 'EX_h_e': 1000.0,
 'EX_nh4_e': 1000.0,
 'EX_pi_e': 1000.0}

As we can see oxygen import is now removed from the list of active exchanges and we can verify that this also leads to a lower growth rate.

In [3]:
model.slim_optimize()
Out[3]:
0.21166294973530736

Setting the growth medium also connects to the context manager, so you can set a specific growth medium in a reversible manner.

In [4]:
model = create_test_model("textbook")

with model:
    medium = model.medium
    medium["EX_o2_e"] = 0.0
    model.medium = medium
    print(model.slim_optimize())
print(model.slim_optimize())
model.medium
0.21166294973530736
0.8739215069684102
Out[4]:
{'EX_co2_e': 1000.0,
 'EX_glc__D_e': 10.0,
 'EX_h2o_e': 1000.0,
 'EX_h_e': 1000.0,
 'EX_nh4_e': 1000.0,
 'EX_o2_e': 1000.0,
 'EX_pi_e': 1000.0}

So the medium change is only applied within the with block and reverted automatically.

10.1. Minimal media

In some cases you might be interested in the smallest growth medium that can maintain a specific growth rate, the so called “minimal medium”. For this we provide the function minimal_medium which by default obtains the medium with the lowest total import flux. This function needs two arguments: the model and the minimum growth rate (or other objective) the model has to achieve.

In [5]:
from cobra.medium import minimal_medium

max_growth = model.slim_optimize()
minimal_medium(model, max_growth)
Out[5]:
EX_glc__D_e    10.000000
EX_nh4_e        4.765319
EX_o2_e        21.799493
EX_pi_e         3.214895
dtype: float64

So we see that growth is actually limited by glucose import.

Alternatively you might be interested in a minimal medium with the smallest number of active imports. This can be achieved by using the minimize_components argument (note that this uses a MIP formulation and will therefore be much slower).

In [6]:
minimal_medium(model, 0.1, minimize_components=True)
Out[6]:
EX_glc__D_e    10.000000
EX_nh4_e        1.042503
EX_pi_e         0.703318
dtype: float64

When minimizing the number of import fluxes there may be many alternative solutions. To obtain several of those you can also pass a positive integer to minimize_components which will give you at most that many alternative solutions. Let us try that with our model and also use the open_exchanges argument which will assign a large upper bound to all import reactions in the model. The return type will be a pandas.DataFrame.

In [7]:
minimal_medium(model, 0.8, minimize_components=8, open_exchanges=True)
Out[7]:
0 1 2 3 4 5
EX_fru_e 0.000000 0.000000 523.104557 0.000000 0.000000 0.000000
EX_glc__D_e 0.000000 0.000000 0.000000 523.104557 521.357767 519.750758
EX_gln__L_e 0.000000 0.000000 0.000000 0.000000 40.698058 0.000000
EX_glu__L_e 23.468185 348.101944 83.995843 83.995843 0.000000 0.000000
EX_mal__L_e 1000.000000 0.000000 0.000000 0.000000 0.000000 0.000000
EX_nh4_e 0.000000 0.000000 0.000000 0.000000 0.000000 81.026921
EX_o2_e 0.000000 500.000000 0.000000 0.000000 0.000000 0.000000
EX_pi_e 15.667461 66.431529 56.667310 56.667310 54.913419 54.664344

So there are 4 alternative solutions in total. One aerobic and three anaerobic ones using different carbon sources.

10.2. Boundary reactions

Apart from exchange reactions there are other types of boundary reactions such as demand or sink reactions. cobrapy uses various heuristics to identify those and they can be accessed by using the appropriate attribute.

For exchange reactions:

In [8]:
ecoli = create_test_model("ecoli")
ecoli.exchanges[0:5]
Out[8]:
[<Reaction EX_12ppd__R_e at 0x7f3921088fd0>,
 <Reaction EX_12ppd__S_e at 0x7f3921078fd0>,
 <Reaction EX_14glucan_e at 0x7f3921078f98>,
 <Reaction EX_15dap_e at 0x7f3921078eb8>,
 <Reaction EX_23camp_e at 0x7f392107e2b0>]

For demand reactions:

In [9]:
ecoli.demands
Out[9]:
[<Reaction DM_4CRSOL at 0x7f3921144b70>,
 <Reaction DM_5DRIB at 0x7f3921078b38>,
 <Reaction DM_AACALD at 0x7f3921078be0>,
 <Reaction DM_AMOB at 0x7f3921078c50>,
 <Reaction DM_MTHTHF at 0x7f3921078cf8>,
 <Reaction DM_OXAM at 0x7f3921078d68>]

For sink reactions:

In [10]:
ecoli.sinks
Out[10]:
[]

All boundary reactions (any reaction that consumes or introduces mass into the system) can be obtained with the boundary attribute:

In [11]:
ecoli.boundary[0:10]
Out[11]:
[<Reaction DM_4CRSOL at 0x7f3921144b70>,
 <Reaction DM_5DRIB at 0x7f3921078b38>,
 <Reaction DM_AACALD at 0x7f3921078be0>,
 <Reaction DM_AMOB at 0x7f3921078c50>,
 <Reaction DM_MTHTHF at 0x7f3921078cf8>,
 <Reaction DM_OXAM at 0x7f3921078d68>,
 <Reaction EX_12ppd__R_e at 0x7f3921088fd0>,
 <Reaction EX_12ppd__S_e at 0x7f3921078fd0>,
 <Reaction EX_14glucan_e at 0x7f3921078f98>,
 <Reaction EX_15dap_e at 0x7f3921078eb8>]