PyCoMo Basics
PyCoMo is a Python Community metabolic Modelling package. In this tutorial, the core features will be presented.
The expected runtime for this notebook is approximately 10-30 minutes.
Setting up PyCoMo
Clone the package from github. Next, we are going to import all the packages we need in this tutorial.
[1]:
from pathlib import Path
import sys
import cobra
import os
Importing PyCoMo
[2]:
import pycomo
pycomo.configure_logger(level="info")
2025-11-24 16:01:37,435 - PyCoMo - INFO - Logger initialized.
Creating a Community Model
The creation of a community model consists of 3 steps:
Loading the member models
Preparing the member models for merging
Creating a community model
Loading the member models
The community model creation process starts with models of the individual members. Note that the quality of the community model heavily depends on the quality of the member models!
In this tutorial we are using metabolic models from the AGORA collection. The models were retrieved from www.vmh.life, and are stored in the data folder of the repository. The selection of models and the resulting community represents a cystic fibrosis airway community, as done by Henson et al. (www.doi.org/10.1128/mSystems.00026-19)
[3]:
test_model_dir = "../data/use_case/henson"
named_models = pycomo.load_named_models_from_dir(test_model_dir)
The models and file names were extracted and stored in named_models. Let’s check the contents:
[4]:
named_models
[4]:
{'Achromobacter_xylosoxidans_NBRC_15126': <Model Achromobacter_xylosoxidans_NBRC_15126 at 0x2ce3c81f310>,
'Actinomyces_naeslundii_str_Howell_279': <Model Actinomyces_naeslundii_str_Howell_279 at 0x2ce4c486110>,
'Burkholderia_cepacia_GG4': <Model Burkholderia_cepacia_GG4 at 0x2ce4de34610>,
'Escherichia_coli_str_K_12_substr_MG1655': <Model Escherichia_coli_str_K_12_substr_MG1655 at 0x2ce4eb14110>,
'Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586': <Model Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586 at 0x2ce50708290>,
'Gemella_haemolysans_ATCC_10379': <Model Gemella_haemolysans_ATCC_10379 at 0x2ce514e81d0>,
'Granulicatella_adiacens_ATCC_49175': <Model Granulicatella_adiacens_ATCC_49175 at 0x2ce51ba0f50>,
'Haemophilus_influenzae_R2846': <Model Haemophilus_influenzae_R2846 at 0x2ce522f0610>,
'Neisseria_flavescens_SK114': <Model Neisseria_flavescens_SK114 at 0x2ce52b30510>,
'Porphyromonas_endodontalis_ATCC_35406': <Model Porphyromonas_endodontalis_ATCC_35406 at 0x2ce53440110>,
'Prevotella_melaninogenica_ATCC_25845': <Model Prevotella_melaninogenica_ATCC_25845 at 0x2ce53f04290>,
'Pseudomonas_aeruginosa_NCGM2_S1': <Model Pseudomonas_aeruginosa_NCGM2_S1 at 0x2ce542f4050>,
'Ralstonia_sp_5_7_47FAA': <Model Ralstonia_sp_5_7_47FAA at 0x2ce5420f490>,
'Rothia_mucilaginosa_DY_18': <Model Rothia_mucilaginosa_DY_18 at 0x2ce55aa00d0>,
'Staphylococcus_aureus_subsp_aureus_USA300_FPR3757': <Model Staphylococcus_aureus_subsp_aureus_USA300_FPR3757 at 0x2ce5634c210>,
'Streptococcus_sanguinis_SK36': <Model Streptococcus_sanguinis_SK36 at 0x2ce56ce00d0>,
'Veillonella_atypica_ACS_049_V_Sch6': <Model Veillonella_atypica_ACS_049_V_Sch6 at 0x2ce576586d0>}
Preparing the models for merging
With the models loaded, the next step is preparing them for merging. This is done by creating SingleOrganismModel objects. Using them, the models will be formatted for compliance with the SBML format. Further, an exchange compartment will be generated under the name medium.
One of the requirements for a community metabolic model is a common biomass function. To construct it, PyCoMo requires the biomass of each member represented as a single metabolite. This biomass metabolite ID can be specified when constructing the SingleOrganismModel objects. However, it can also be found or generated automatically, by setting the biomass reaction as the objective of the model. Let’s check if the biomass function is the objective in all the models
[5]:
for model in named_models.values():
print(model.objective)
Maximize
1.0*biomass489 - 1.0*biomass489_reverse_62d1a
Maximize
1.0*biomass492 - 1.0*biomass492_reverse_bc961
Maximize
1.0*biomass479 - 1.0*biomass479_reverse_1d1b2
Maximize
1.0*biomass525 - 1.0*biomass525_reverse_5c178
Maximize
1.0*biomass237 - 1.0*biomass237_reverse_f032e
Maximize
1.0*biomass027 - 1.0*biomass027_reverse_af8dc
Maximize
1.0*biomass091 - 1.0*biomass091_reverse_7b6db
Maximize
1.0*biomass252 - 1.0*biomass252_reverse_f6948
Maximize
1.0*biomass339 - 1.0*biomass339_reverse_45ed6
Maximize
1.0*biomass326 - 1.0*biomass326_reverse_02060
Maximize
1.0*biomass276 - 1.0*biomass276_reverse_7f92e
Maximize
1.0*biomass345 - 1.0*biomass345_reverse_e128f
Maximize
1.0*biomass525 - 1.0*biomass525_reverse_5c178
Maximize
1.0*biomass429 - 1.0*biomass429_reverse_9caa0
Maximize
1.0*biomass042 - 1.0*biomass042_reverse_2a02b
Maximize
1.0*biomass164 - 1.0*biomass164_reverse_ca493
Maximize
1.0*biomass116 - 1.0*biomass116_reverse_02324
With the objective being the biomass function in all models, the biomass metabolite does not need to be specified.
[6]:
single_org_models = []
for name, model in named_models.items():
print(name)
single_org_model = pycomo.SingleOrganismModel(model, name)
single_org_models.append(single_org_model)
Achromobacter_xylosoxidans_NBRC_15126
Actinomyces_naeslundii_str_Howell_279
Burkholderia_cepacia_GG4
Escherichia_coli_str_K_12_substr_MG1655
Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586
Gemella_haemolysans_ATCC_10379
Granulicatella_adiacens_ATCC_49175
Haemophilus_influenzae_R2846
Neisseria_flavescens_SK114
Porphyromonas_endodontalis_ATCC_35406
Prevotella_melaninogenica_ATCC_25845
Pseudomonas_aeruginosa_NCGM2_S1
Ralstonia_sp_5_7_47FAA
Rothia_mucilaginosa_DY_18
Staphylococcus_aureus_subsp_aureus_USA300_FPR3757
Streptococcus_sanguinis_SK36
Veillonella_atypica_ACS_049_V_Sch6
Creating a community model
With the member models prepared, the community model can be generated. The first step is to create a CommunityModel objects from the member models. The matching of the exchange metabolites can be achieved in two ways: matching via identical metabolite IDs, or via annotation fields. In this tutorial and as all the models come from the same source, matching via identical metabolite IDs will be used.
[7]:
community_name = "henson_community_model"
com_model_obj = pycomo.CommunityModel(single_org_models, community_name)
The cobra model of the community will generated the first time it is needed. We can enforce this now, by calling it via .model
[8]:
com_model_obj.model
2025-11-24 16:02:05,522 - PyCoMo - INFO - No community model generated yet. Generating now:
2025-11-24 16:02:06,335 - PyCoMo - INFO - Identified biomass reaction from objective: biomass489
2025-11-24 16:02:06,336 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:02:23,825 - PyCoMo - INFO - Identified biomass reaction from objective: biomass492
2025-11-24 16:02:23,826 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:02:33,547 - PyCoMo - INFO - Identified biomass reaction from objective: biomass479
2025-11-24 16:02:33,548 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:02:52,332 - PyCoMo - INFO - Identified biomass reaction from objective: biomass525
2025-11-24 16:02:52,333 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:03:14,371 - PyCoMo - INFO - Identified biomass reaction from objective: biomass237
2025-11-24 16:03:14,371 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:03:22,627 - PyCoMo - INFO - Identified biomass reaction from objective: biomass027
2025-11-24 16:03:22,627 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:03:28,923 - PyCoMo - INFO - Identified biomass reaction from objective: biomass091
2025-11-24 16:03:28,923 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:03:35,123 - PyCoMo - INFO - Identified biomass reaction from objective: biomass252
2025-11-24 16:03:35,124 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:03:45,360 - PyCoMo - INFO - Identified biomass reaction from objective: biomass339
2025-11-24 16:03:45,361 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:03:54,205 - PyCoMo - INFO - Identified biomass reaction from objective: biomass326
2025-11-24 16:03:54,206 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:04:00,594 - PyCoMo - INFO - Identified biomass reaction from objective: biomass276
2025-11-24 16:04:00,594 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:04:08,554 - PyCoMo - INFO - Identified biomass reaction from objective: biomass345
2025-11-24 16:04:08,554 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:04:23,571 - PyCoMo - INFO - Identified biomass reaction from objective: biomass525
2025-11-24 16:04:23,572 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:04:36,766 - PyCoMo - INFO - Identified biomass reaction from objective: biomass429
2025-11-24 16:04:36,767 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:04:45,277 - PyCoMo - INFO - Identified biomass reaction from objective: biomass042
2025-11-24 16:04:45,278 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:04:58,259 - PyCoMo - INFO - Identified biomass reaction from objective: biomass164
2025-11-24 16:04:58,260 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:05:08,726 - PyCoMo - INFO - Identified biomass reaction from objective: biomass116
2025-11-24 16:05:08,727 - PyCoMo - INFO - Note: no products in the objective function, adding biomass to it.
2025-11-24 16:05:17,280 - PyCoMo - WARNING - No annotation overlap found for matching several metabolites (552). Please make sure that the matched metabolites are indeed representing the same substance in all models! The list of metaboliteswithout annotation overlap can be accessed via 'model.no_annotation_overlap'
2025-11-24 16:05:38,198 - PyCoMo - WARNING - Not all reactions in the model are mass and charge balanced. To check which reactions are imbalanced, please run the get_unbalanced_reactions method of this CommunityModel object
2025-11-24 16:05:38,199 - PyCoMo - INFO - Generated community model.
[8]:
| Name | henson_community_model |
| Memory address | 2ce57f4d790 |
| Number of metabolites | 51664 |
| Number of reactions | 55176 |
| Number of genes | 13885 |
| Number of groups | 80 |
| Objective expression | 1.0*community_biomass - 1.0*community_biomass_reverse_44dc1 |
| Compartments | Achromobacter_xylosoxidans_NBRC_15126_c, Achromobacter_xylosoxidans_NBRC_15126_e, Achromobacter_xylosoxidans_NBRC_15126_medium, medium, fraction_reaction, Actinomyces_naeslundii_str_Howell_279_c, Actinomyces_naeslundii_str_Howell_279_e, Actinomyces_naeslundii_str_Howell_279_medium, Burkholderia_cepacia_GG4_e, Burkholderia_cepacia_GG4_c, Burkholderia_cepacia_GG4_medium, Escherichia_coli_str_K_12_substr_MG1655_e, Escherichia_coli_str_K_12_substr_MG1655_c, Escherichia_coli_str_K_12_substr_MG1655_medium, Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586_c, Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586_e, Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586_medium, Gemella_haemolysans_ATCC_10379_c, Gemella_haemolysans_ATCC_10379_e, Gemella_haemolysans_ATCC_10379_medium, Granulicatella_adiacens_ATCC_49175_e, Granulicatella_adiacens_ATCC_49175_c, Granulicatella_adiacens_ATCC_49175_medium, Haemophilus_influenzae_R2846_c, Haemophilus_influenzae_R2846_e, Haemophilus_influenzae_R2846_medium, Neisseria_flavescens_SK114_c, Neisseria_flavescens_SK114_e, Neisseria_flavescens_SK114_medium, Porphyromonas_endodontalis_ATCC_35406_c, Porphyromonas_endodontalis_ATCC_35406_e, Porphyromonas_endodontalis_ATCC_35406_medium, Prevotella_melaninogenica_ATCC_25845_c, Prevotella_melaninogenica_ATCC_25845_e, Prevotella_melaninogenica_ATCC_25845_medium, Pseudomonas_aeruginosa_NCGM2_S1_c, Pseudomonas_aeruginosa_NCGM2_S1_e, Pseudomonas_aeruginosa_NCGM2_S1_medium, Ralstonia_sp_5_7_47FAA_c, Ralstonia_sp_5_7_47FAA_e, Ralstonia_sp_5_7_47FAA_medium, Rothia_mucilaginosa_DY_18_c, Rothia_mucilaginosa_DY_18_e, Rothia_mucilaginosa_DY_18_medium, Staphylococcus_aureus_subsp_aureus_USA300_FPR3757_e, Staphylococcus_aureus_subsp_aureus_USA300_FPR3757_c, Staphylococcus_aureus_subsp_aureus_USA300_FPR3757_medium, Streptococcus_sanguinis_SK36_e, Streptococcus_sanguinis_SK36_c, Streptococcus_sanguinis_SK36_medium, Veillonella_atypica_ACS_049_V_Sch6_c, Veillonella_atypica_ACS_049_V_Sch6_e, Veillonella_atypica_ACS_049_V_Sch6_medium |
The output of the community model creation contains quite some lines of info and warnings. This is to be expected. Let’s have a look at the different types of info:
Ignoring reaction ‘EX_4abz_medium’ since it already exists. This line will come up if a reaction is present in two different community member models under the same ID. This will only happen for exchange reactions in the exchange compartment and are therefor correct behaviour.
WARNING: no annotation overlap found for matching metabolite mn2. Please make sure that the metabolite with this ID is indeed representing the same substance in all models! This warning comes up if exchange metabolites do not contain any matching annotation field. This can be an indicator that metabolites with the same ID are merged, but they represent different chemicals. Another common cause is that no annotation was given for this metabolite in one of the models.
WARNING: matching of the metabolite CO2_EX is unbalanced (mass and/or charge). Please manually curate this metabolite for a mass and charge balanced model! This warning means that the formula of an exchange metabolite was different between member models. This can be due to the formula being omitted in some of the models. The other reason is that the metabolites differ in their mass or charge. As this would lead to generation or loss of matter from nothing, these issues need to be resolved for a consistent metabolic model.
Summary and report
The community model object has two utility methods to display information on the model.
Summary behaves the same as the summary method of COBRApy, displaying the the solution of FBA and its exchange metabolites. In the CommunityModel summary, the exchange reactions of metabolites responsible for scaling the flux bounds to the community composition are hidden.
The report function displays information on the model structure: the number of metabolites, reactions, genes, etc., but also quality control measures on mass and charge balance and internal loops.
[9]:
com_model_obj.summary()
[9]:
Objective
1.0 community_biomass = 1.0
Uptake
| Metabolite | Reaction | Flux | C-Number | C-Flux |
|---|---|---|---|---|
| _26dap_M_medium | EX__26dap_M_medium | 0.02501 | 7 | 0.06% |
| _2dmmq8_medium | EX__2dmmq8_medium | 0.003097 | 50 | 0.05% |
| adn_medium | EX_adn_medium | 3.582 | 10 | 12.59% |
| ala_L_medium | EX_ala_L_medium | 0.503 | 3 | 0.53% |
| amp_medium | EX_amp_medium | 0.8121 | 10 | 2.86% |
| arg_L_medium | EX_arg_L_medium | 8.031 | 6 | 16.94% |
| asn_L_medium | EX_asn_L_medium | 0.2008 | 4 | 0.28% |
| asp_L_medium | EX_asp_L_medium | 0.2008 | 4 | 0.28% |
| ca2_medium | EX_ca2_medium | 0.003097 | 0 | 0.00% |
| cgly_medium | EX_cgly_medium | 0.003097 | 5 | 0.01% |
| cl_medium | EX_cl_medium | 0.003097 | 0 | 0.00% |
| cobalt2_medium | EX_cobalt2_medium | 0.003096 | 0 | 0.00% |
| cu2_medium | EX_cu2_medium | 0.003097 | 0 | 0.00% |
| cys_L_medium | EX_cys_L_medium | 0.08234 | 3 | 0.09% |
| cytd_medium | EX_cytd_medium | 0.09933 | 9 | 0.31% |
| dad_2_medium | EX_dad_2_medium | 7.679 | 10 | 27.00% |
| dgsn_medium | EX_dgsn_medium | 0.1599 | 10 | 0.56% |
| fe2_medium | EX_fe2_medium | 0.003096 | 0 | 0.00% |
| fe3_medium | EX_fe3_medium | 0.003097 | 0 | 0.00% |
| gln_L_medium | EX_gln_L_medium | 0.2074 | 5 | 0.36% |
| glyleu_medium | EX_glyleu_medium | 0.4606 | 8 | 1.30% |
| h_medium | EX_h_medium | 1.543 | 0 | 0.00% |
| his_L_medium | EX_his_L_medium | 0.3013 | 6 | 0.64% |
| ile_L_medium | EX_ile_L_medium | 0.327 | 6 | 0.69% |
| k_medium | EX_k_medium | 0.003097 | 0 | 0.00% |
| lys_L_medium | EX_lys_L_medium | 0.2854 | 6 | 0.60% |
| met_L_medium | EX_met_L_medium | 0.134 | 5 | 0.24% |
| mg2_medium | EX_mg2_medium | 0.003096 | 0 | 0.00% |
| mn2_medium | EX_mn2_medium | 0.003096 | 0 | 0.00% |
| mqn8_medium | EX_mqn8_medium | 0.003097 | 51 | 0.06% |
| nac_medium | EX_nac_medium | 0.006193 | 6 | 0.01% |
| o2_medium | EX_o2_medium | 0.003097 | 0 | 0.00% |
| phe_L_medium | EX_phe_L_medium | 0.1545 | 9 | 0.49% |
| pheme_medium | EX_pheme_medium | 0.003097 | 34 | 0.04% |
| pnto_R_medium | EX_pnto_R_medium | 0.006193 | 9 | 0.02% |
| pro_L_medium | EX_pro_L_medium | 0.1844 | 5 | 0.32% |
| ptrc_medium | EX_ptrc_medium | 0.003097 | 4 | 0.00% |
| q8_medium | EX_q8_medium | 0.003097 | 49 | 0.05% |
| ribflv_medium | EX_ribflv_medium | 0.006193 | 17 | 0.04% |
| sheme_medium | EX_sheme_medium | 0.003097 | 42 | 0.05% |
| so4_medium | EX_so4_medium | 0.003096 | 0 | 0.00% |
| spmd_medium | EX_spmd_medium | 0.003096 | 7 | 0.01% |
| succ_medium | EX_succ_medium | 0.0462 | 4 | 0.06% |
| thm_medium | EX_thm_medium | 0.003097 | 12 | 0.01% |
| thr_L_medium | EX_thr_L_medium | 0.4718 | 4 | 0.66% |
| trp_L_medium | EX_trp_L_medium | 0.0472 | 11 | 0.18% |
| ttdca_medium | EX_ttdca_medium | 0.1501 | 14 | 0.74% |
| tyr_L_medium | EX_tyr_L_medium | 0.1207 | 9 | 0.38% |
| uri_medium | EX_uri_medium | 9.752 | 9 | 30.86% |
| val_L_medium | EX_val_L_medium | 0.3522 | 5 | 0.62% |
| zn2_medium | EX_zn2_medium | 0.003096 | 0 | 0.00% |
Secretion
| Metabolite | Reaction | Flux | C-Number | C-Flux |
|---|---|---|---|---|
| acald_medium | EX_acald_medium | -8.505 | 2 | 6.94% |
| ade_medium | EX_ade_medium | -11.93 | 5 | 24.33% |
| but_medium | EX_but_medium | -5.478 | 4 | 8.94% |
| co2_medium | EX_co2_medium | -20.76 | 1 | 8.47% |
| dcyt_medium | EX_dcyt_medium | -9.644 | 9 | 35.42% |
| gcald_medium | EX_gcald_medium | -0.00929 | 2 | 0.01% |
| nh4_medium | EX_nh4_medium | -6.363 | 0 | 0.00% |
| orn_medium | EX_orn_medium | -7.785 | 5 | 15.88% |
| cpd11416_medium | community_biomass | -1 | 0 | 0.00% |
[10]:
com_model_obj.report();
2025-11-24 16:06:49,241 - PyCoMo - INFO - Note: The model has more than 5000 reactions. Calculation of loops is skipped, as this would take some time. If needed, please run manually via .get_loops()
2025-11-24 16:06:49,242 - PyCoMo - INFO - Name: henson_community_model
2025-11-24 16:06:49,242 - PyCoMo - INFO - ------------------
2025-11-24 16:06:49,243 - PyCoMo - INFO - Model overview
2025-11-24 16:06:49,243 - PyCoMo - INFO - Model structure: fixed growth rate
2025-11-24 16:06:49,244 - PyCoMo - INFO - # Metabolites: 51664
2025-11-24 16:06:49,244 - PyCoMo - INFO - # Constraint (f-) Metabolites: 31974
2025-11-24 16:06:49,244 - PyCoMo - INFO - # Model Metabolites: 19690
2025-11-24 16:06:49,245 - PyCoMo - INFO - # Reactions: 55176
2025-11-24 16:06:49,245 - PyCoMo - INFO - # Constraint (f-) Reactions: 31974
2025-11-24 16:06:49,245 - PyCoMo - INFO - # Model Reactions: 23202
2025-11-24 16:06:49,246 - PyCoMo - INFO - # Genes: 13885
2025-11-24 16:06:49,246 - PyCoMo - INFO - # Members: 17
2025-11-24 16:06:49,246 - PyCoMo - INFO - Members:
2025-11-24 16:06:49,246 - PyCoMo - INFO - Achromobacter_xylosoxidans_NBRC_15126
2025-11-24 16:06:49,247 - PyCoMo - INFO - Actinomyces_naeslundii_str_Howell_279
2025-11-24 16:06:49,247 - PyCoMo - INFO - Burkholderia_cepacia_GG4
2025-11-24 16:06:49,247 - PyCoMo - INFO - Escherichia_coli_str_K_12_substr_MG1655
2025-11-24 16:06:49,248 - PyCoMo - INFO - Fusobacterium_nucleatum_subsp_nucleatum_ATCC_25586
2025-11-24 16:06:49,248 - PyCoMo - INFO - Gemella_haemolysans_ATCC_10379
2025-11-24 16:06:49,248 - PyCoMo - INFO - Granulicatella_adiacens_ATCC_49175
2025-11-24 16:06:49,249 - PyCoMo - INFO - Haemophilus_influenzae_R2846
2025-11-24 16:06:49,249 - PyCoMo - INFO - Neisseria_flavescens_SK114
2025-11-24 16:06:49,249 - PyCoMo - INFO - Porphyromonas_endodontalis_ATCC_35406
2025-11-24 16:06:49,250 - PyCoMo - INFO - Prevotella_melaninogenica_ATCC_25845
2025-11-24 16:06:49,250 - PyCoMo - INFO - Pseudomonas_aeruginosa_NCGM2_S1
2025-11-24 16:06:49,250 - PyCoMo - INFO - Ralstonia_sp_5_7_47FAA
2025-11-24 16:06:49,250 - PyCoMo - INFO - Rothia_mucilaginosa_DY_18
2025-11-24 16:06:49,251 - PyCoMo - INFO - Staphylococcus_aureus_subsp_aureus_USA300_FPR3757
2025-11-24 16:06:49,251 - PyCoMo - INFO - Streptococcus_sanguinis_SK36
2025-11-24 16:06:49,252 - PyCoMo - INFO - Veillonella_atypica_ACS_049_V_Sch6
2025-11-24 16:06:49,252 - PyCoMo - INFO - Objective in direction max:
1.0*community_biomass - 1.0*community_biomass_reverse_44dc1
2025-11-24 16:06:49,253 - PyCoMo - INFO - ------------------
2025-11-24 16:06:49,253 - PyCoMo - INFO - Model quality
2025-11-24 16:06:49,253 - PyCoMo - INFO - # Reactions unbalanced: 235
2025-11-24 16:06:49,254 - PyCoMo - INFO - # Reactions able to carry flux without a medium: NaN
Setting the growth rate
By default the community model object will have the structure of fixe growth rate. This means, the fractions of the community member abundance is allowed to vary during simulations, but the individual and community growth rate is set to a fixed value (default: 1.0). The next thing we will try is to set the community growth rate to a different value and do a FBA.
[11]:
com_model_obj.apply_fixed_growth_rate(0.5)
com_model_obj.summary()
[11]:
Objective
1.0 community_biomass = 0.5
Uptake
| Metabolite | Reaction | Flux | C-Number | C-Flux |
|---|---|---|---|---|
| _26dap_M_medium | EX__26dap_M_medium | 0.01251 | 7 | 0.06% |
| _2dmmq8_medium | EX__2dmmq8_medium | 0.001548 | 50 | 0.05% |
| adn_medium | EX_adn_medium | 1.791 | 10 | 12.59% |
| ala_L_medium | EX_ala_L_medium | 0.2515 | 3 | 0.53% |
| amp_medium | EX_amp_medium | 0.406 | 10 | 2.86% |
| arg_L_medium | EX_arg_L_medium | 4.016 | 6 | 16.94% |
| asn_L_medium | EX_asn_L_medium | 0.1004 | 4 | 0.28% |
| asp_L_medium | EX_asp_L_medium | 0.1004 | 4 | 0.28% |
| ca2_medium | EX_ca2_medium | 0.001548 | 0 | 0.00% |
| cgly_medium | EX_cgly_medium | 0.001548 | 5 | 0.01% |
| cl_medium | EX_cl_medium | 0.001548 | 0 | 0.00% |
| cobalt2_medium | EX_cobalt2_medium | 0.001548 | 0 | 0.00% |
| cu2_medium | EX_cu2_medium | 0.001548 | 0 | 0.00% |
| cys_L_medium | EX_cys_L_medium | 0.04117 | 3 | 0.09% |
| cytd_medium | EX_cytd_medium | 0.04967 | 9 | 0.31% |
| dad_2_medium | EX_dad_2_medium | 3.839 | 10 | 27.00% |
| dgsn_medium | EX_dgsn_medium | 0.07996 | 10 | 0.56% |
| fe2_medium | EX_fe2_medium | 0.001548 | 0 | 0.00% |
| fe3_medium | EX_fe3_medium | 0.001548 | 0 | 0.00% |
| gln_L_medium | EX_gln_L_medium | 0.1037 | 5 | 0.36% |
| glyleu_medium | EX_glyleu_medium | 0.2303 | 8 | 1.30% |
| h_medium | EX_h_medium | 0.7715 | 0 | 0.00% |
| his_L_medium | EX_his_L_medium | 0.1506 | 6 | 0.64% |
| ile_L_medium | EX_ile_L_medium | 0.1635 | 6 | 0.69% |
| k_medium | EX_k_medium | 0.001548 | 0 | 0.00% |
| lys_L_medium | EX_lys_L_medium | 0.1427 | 6 | 0.60% |
| met_L_medium | EX_met_L_medium | 0.067 | 5 | 0.24% |
| mg2_medium | EX_mg2_medium | 0.001548 | 0 | 0.00% |
| mn2_medium | EX_mn2_medium | 0.001548 | 0 | 0.00% |
| mqn8_medium | EX_mqn8_medium | 0.001548 | 51 | 0.06% |
| nac_medium | EX_nac_medium | 0.003097 | 6 | 0.01% |
| o2_medium | EX_o2_medium | 0.001548 | 0 | 0.00% |
| phe_L_medium | EX_phe_L_medium | 0.07726 | 9 | 0.49% |
| pheme_medium | EX_pheme_medium | 0.001548 | 34 | 0.04% |
| pnto_R_medium | EX_pnto_R_medium | 0.003096 | 9 | 0.02% |
| pro_L_medium | EX_pro_L_medium | 0.09218 | 5 | 0.32% |
| ptrc_medium | EX_ptrc_medium | 0.001548 | 4 | 0.00% |
| q8_medium | EX_q8_medium | 0.001548 | 49 | 0.05% |
| ribflv_medium | EX_ribflv_medium | 0.003097 | 17 | 0.04% |
| sheme_medium | EX_sheme_medium | 0.001548 | 42 | 0.05% |
| so4_medium | EX_so4_medium | 0.001548 | 0 | 0.00% |
| spmd_medium | EX_spmd_medium | 0.001548 | 7 | 0.01% |
| succ_medium | EX_succ_medium | 0.0231 | 4 | 0.06% |
| thm_medium | EX_thm_medium | 0.001548 | 12 | 0.01% |
| thr_L_medium | EX_thr_L_medium | 0.2359 | 4 | 0.66% |
| trp_L_medium | EX_trp_L_medium | 0.0236 | 11 | 0.18% |
| ttdca_medium | EX_ttdca_medium | 0.07503 | 14 | 0.74% |
| tyr_L_medium | EX_tyr_L_medium | 0.06034 | 9 | 0.38% |
| uri_medium | EX_uri_medium | 4.876 | 9 | 30.86% |
| val_L_medium | EX_val_L_medium | 0.1761 | 5 | 0.62% |
| zn2_medium | EX_zn2_medium | 0.001548 | 0 | 0.00% |
Secretion
| Metabolite | Reaction | Flux | C-Number | C-Flux |
|---|---|---|---|---|
| acald_medium | EX_acald_medium | -4.252 | 2 | 6.94% |
| ade_medium | EX_ade_medium | -5.963 | 5 | 24.33% |
| but_medium | EX_but_medium | -2.739 | 4 | 8.94% |
| co2_medium | EX_co2_medium | -10.38 | 1 | 8.47% |
| dcyt_medium | EX_dcyt_medium | -4.822 | 9 | 35.42% |
| gcald_medium | EX_gcald_medium | -0.004645 | 2 | 0.01% |
| nh4_medium | EX_nh4_medium | -3.182 | 0 | 0.00% |
| orn_medium | EX_orn_medium | -3.892 | 5 | 15.88% |
| cpd11416_medium | community_biomass | -0.5 | 0 | 0.00% |
Setting the community member composition
The model structure can be changed to fixed abundance, but variable growth rate. To do so, a conversion function needs to be called. Here we then change the community abundance to equal abundances.
[12]:
com_model_obj.convert_to_fixed_abundance()
abundance_dict = com_model_obj.generate_equal_abundance_dict()
com_model_obj.apply_fixed_abundance(abundance_dict)
com_model_obj.summary()
[12]:
Objective
1.0 community_biomass = 43.8482024141438
Uptake
| Metabolite | Reaction | Flux | C-Number | C-Flux |
|---|---|---|---|---|
| _12dgr180_medium | EX__12dgr180_medium | 0.3429 | 39 | 0.19% |
| _26dap_M_medium | EX__26dap_M_medium | 0.4749 | 7 | 0.05% |
| _2dmmq8_medium | EX__2dmmq8_medium | 0.1014 | 50 | 0.07% |
| _2obut_medium | EX__2obut_medium | 106.7 | 4 | 6.13% |
| _3mop_medium | EX__3mop_medium | 18.17 | 6 | 1.57% |
| _4abz_medium | EX__4abz_medium | 0.0854 | 7 | 0.01% |
| _4hbz_medium | EX__4hbz_medium | 0.05693 | 7 | 0.01% |
| _5mta_medium | EX__5mta_medium | 0.3696 | 11 | 0.06% |
| acgam_medium | EX_acgam_medium | 36.1 | 8 | 4.15% |
| acnam_medium | EX_acnam_medium | 1.502 | 11 | 0.24% |
| actn_R_medium | EX_actn_R_medium | 52.66 | 4 | 3.02% |
| adn_medium | EX_adn_medium | 10.79 | 10 | 1.55% |
| alagln_medium | EX_alagln_medium | 49.46 | 8 | 5.68% |
| alahis_medium | EX_alahis_medium | 13.11 | 9 | 1.69% |
| alathr_medium | EX_alathr_medium | 5.759 | 7 | 0.58% |
| amp_medium | EX_amp_medium | 6.277 | 10 | 0.90% |
| arab_D_medium | EX_arab_D_medium | 0.1935 | 5 | 0.01% |
| arg_L_medium | EX_arg_L_medium | 46.94 | 6 | 4.04% |
| asn_L_medium | EX_asn_L_medium | 6.255 | 4 | 0.36% |
| ca2_medium | EX_ca2_medium | 0.2225 | 0 | 0.00% |
| cgly_medium | EX_cgly_medium | 0.702 | 5 | 0.05% |
| chtbs_medium | EX_chtbs_medium | 7.657 | 16 | 1.76% |
| cit_medium | EX_cit_medium | 17.49 | 6 | 1.51% |
| cl_medium | EX_cl_medium | 0.2225 | 0 | 0.00% |
| cobalt2_medium | EX_cobalt2_medium | 0.2225 | 0 | 0.00% |
| cu2_medium | EX_cu2_medium | 0.2225 | 0 | 0.00% |
| cys_L_medium | EX_cys_L_medium | 2.619 | 3 | 0.11% |
| cytd_medium | EX_cytd_medium | 2.429 | 9 | 0.31% |
| dad_2_medium | EX_dad_2_medium | 48.65 | 10 | 6.99% |
| ddca_medium | EX_ddca_medium | 0.6451 | 12 | 0.11% |
| dgsn_medium | EX_dgsn_medium | 14.45 | 10 | 2.08% |
| duri_medium | EX_duri_medium | 0.02266 | 9 | 0.00% |
| fe2_medium | EX_fe2_medium | 0.1406 | 0 | 0.00% |
| fe3_medium | EX_fe3_medium | 0.3489 | 0 | 0.00% |
| fol_medium | EX_fol_medium | 0.3895 | 19 | 0.11% |
| fru_medium | EX_fru_medium | 56.58 | 6 | 4.87% |
| fum_medium | EX_fum_medium | 15.88 | 4 | 0.91% |
| gam_medium | EX_gam_medium | 6.405 | 6 | 0.55% |
| gcald_medium | EX_gcald_medium | 0.05684 | 2 | 0.00% |
| glc_D_medium | EX_glc_D_medium | 12.05 | 6 | 1.04% |
| gln_L_medium | EX_gln_L_medium | 52.19 | 5 | 3.75% |
| glyasn_medium | EX_glyasn_medium | 55.54 | 6 | 4.78% |
| glyc3p_medium | EX_glyc3p_medium | 88.1 | 3 | 3.79% |
| glycys_medium | EX_glycys_medium | 0.3757 | 5 | 0.03% |
| glyleu_medium | EX_glyleu_medium | 76 | 8 | 8.73% |
| glymet_medium | EX_glymet_medium | 0.3696 | 7 | 0.04% |
| glyphe_medium | EX_glyphe_medium | 1.818 | 11 | 0.29% |
| glypro_medium | EX_glypro_medium | 11.66 | 7 | 1.17% |
| glytyr_medium | EX_glytyr_medium | 1.146 | 11 | 0.18% |
| gsn_medium | EX_gsn_medium | 0.3892 | 10 | 0.06% |
| gthox_medium | EX_gthox_medium | 0.003993 | 20 | 0.00% |
| gthrd_medium | EX_gthrd_medium | 0.03195 | 10 | 0.00% |
| his_L_medium | EX_his_L_medium | 2.319 | 6 | 0.20% |
| hxan_medium | EX_hxan_medium | 2.697 | 5 | 0.19% |
| inulin_medium | EX_inulin_medium | 0.6138 | 180 | 1.59% |
| k_medium | EX_k_medium | 0.2225 | 0 | 0.00% |
| lys_L_medium | EX_lys_L_medium | 13.26 | 6 | 1.14% |
| man_medium | EX_man_medium | 7.107 | 6 | 0.61% |
| met_L_medium | EX_met_L_medium | 2.034 | 5 | 0.15% |
| metala_medium | EX_metala_medium | 3.297 | 8 | 0.38% |
| mg2_medium | EX_mg2_medium | 0.2225 | 0 | 0.00% |
| mn2_medium | EX_mn2_medium | 0.2225 | 0 | 0.00% |
| mqn7_medium | EX_mqn7_medium | 0.04792 | 46 | 0.03% |
| mqn8_medium | EX_mqn8_medium | 0.1173 | 51 | 0.09% |
| ncam_medium | EX_ncam_medium | 0.01597 | 6 | 0.00% |
| nmn_medium | EX_nmn_medium | 12.43 | 11 | 1.96% |
| no3_medium | EX_no3_medium | 0.4119 | 0 | 0.00% |
| o2_medium | EX_o2_medium | 227 | 0 | 0.00% |
| ocdca_medium | EX_ocdca_medium | 2.289 | 18 | 0.59% |
| phe_L_medium | EX_phe_L_medium | 4.973 | 9 | 0.64% |
| pheme_medium | EX_pheme_medium | 0.1823 | 34 | 0.09% |
| phpyr_medium | EX_phpyr_medium | 0.3986 | 9 | 0.05% |
| pnto_R_medium | EX_pnto_R_medium | 0.243 | 9 | 0.03% |
| pro_L_medium | EX_pro_L_medium | 21.15 | 5 | 1.52% |
| ptrc_medium | EX_ptrc_medium | 0.1184 | 4 | 0.01% |
| pullulan1200_medium | EX_pullulan1200_medium | 0.02527 | 7200 | 2.61% |
| pydx_medium | EX_pydx_medium | 0.1864 | 8 | 0.02% |
| pyr_medium | EX_pyr_medium | 38.37 | 3 | 1.65% |
| q8_medium | EX_q8_medium | 0.1094 | 49 | 0.08% |
| ribflv_medium | EX_ribflv_medium | 0.1958 | 17 | 0.05% |
| ser_L_medium | EX_ser_L_medium | 48.29 | 3 | 2.08% |
| sheme_medium | EX_sheme_medium | 0.1378 | 42 | 0.08% |
| so4_medium | EX_so4_medium | 0.2225 | 0 | 0.00% |
| spmd_medium | EX_spmd_medium | 0.1743 | 7 | 0.02% |
| stys_medium | EX_stys_medium | 0.2655 | 24 | 0.09% |
| sucr_medium | EX_sucr_medium | 26.43 | 12 | 4.55% |
| thm_medium | EX_thm_medium | 0.1823 | 12 | 0.03% |
| thr_L_medium | EX_thr_L_medium | 12.32 | 4 | 0.71% |
| thymd_medium | EX_thymd_medium | 0.3716 | 10 | 0.05% |
| trp_L_medium | EX_trp_L_medium | 1.641 | 11 | 0.26% |
| ttdca_medium | EX_ttdca_medium | 2.129 | 14 | 0.43% |
| tyr_L_medium | EX_tyr_L_medium | 12.37 | 9 | 1.60% |
| uri_medium | EX_uri_medium | 14.92 | 9 | 1.93% |
| val_L_medium | EX_val_L_medium | 13.35 | 5 | 0.96% |
| zn2_medium | EX_zn2_medium | 0.2225 | 0 | 0.00% |
Secretion
| Metabolite | Reaction | Flux | C-Number | C-Flux |
|---|---|---|---|---|
| _4hphac_medium | EX__4hphac_medium | -8.28 | 8 | 1.26% |
| ac_medium | EX_ac_medium | -571.2 | 2 | 21.74% |
| ade_medium | EX_ade_medium | -61.57 | 5 | 5.86% |
| ala_L_medium | EX_ala_L_medium | -7.231 | 3 | 0.41% |
| asp_L_medium | EX_asp_L_medium | -94.37 | 4 | 7.18% |
| but_medium | EX_but_medium | -23.2 | 4 | 1.77% |
| co2_medium | EX_co2_medium | -101.8 | 1 | 1.94% |
| etoh_medium | EX_etoh_medium | -71.47 | 2 | 2.72% |
| for_medium | EX_for_medium | -384.4 | 1 | 7.32% |
| glu_L_medium | EX_glu_L_medium | -107.5 | 5 | 10.23% |
| gly_medium | EX_gly_medium | -115.9 | 2 | 4.41% |
| gua_medium | EX_gua_medium | -10.17 | 5 | 0.97% |
| h2o_medium | EX_h2o_medium | -521.8 | 0 | 0.00% |
| h2s_medium | EX_h2s_medium | -0.1468 | 0 | 0.00% |
| ile_L_medium | EX_ile_L_medium | -4.345 | 6 | 0.50% |
| lac_D_medium | EX_lac_D_medium | -72.18 | 3 | 4.12% |
| lac_L_medium | EX_lac_L_medium | -13.8 | 3 | 0.79% |
| leu_L_medium | EX_leu_L_medium | -56.74 | 6 | 6.48% |
| mal_L_medium | EX_mal_L_medium | -66.11 | 4 | 5.03% |
| nac_medium | EX_nac_medium | -12 | 6 | 1.37% |
| nh4_medium | EX_nh4_medium | -336.8 | 0 | 0.00% |
| orn_medium | EX_orn_medium | -33.57 | 5 | 3.19% |
| pi_medium | EX_pi_medium | -32.8 | 0 | 0.00% |
| ppa_medium | EX_ppa_medium | -109.6 | 3 | 6.26% |
| ppi_medium | EX_ppi_medium | -15.5 | 0 | 0.00% |
| succ_medium | EX_succ_medium | -71.57 | 4 | 5.45% |
| ura_medium | EX_ura_medium | -11.12 | 4 | 0.85% |
| urea_medium | EX_urea_medium | -8.377 | 1 | 0.16% |
| cpd11416_medium | community_biomass | -43.85 | 0 | 0.00% |
Saving and loading community models
Community model objects can be saved and loaded into SBML files. This is different from the other available option to save the cobra model of the community model objects, as the abundance fractions of the organisms are written into the file as well. Saving and loading the community model can be done like this:
[13]:
com_model_obj.save("../data/toy/output/henson_com_model.xml")
[14]:
com_model_obj_loaded = pycomo.CommunityModel.load("../data/toy/output/henson_com_model.xml")
[15]:
com_model_obj_loaded
[15]:
<pycomo.pycomo_models.CommunityModel at 0x2cf41341dd0>
[16]:
com_model_obj_loaded.model.optimize()
[16]:
| fluxes | reduced_costs | |
|---|---|---|
| Achromobacter_xylosoxidans_NBRC_15126__1H2NPTH_Achromobacter_xylosoxidans_NBRC_15126_c | 0.000000 | -2.863874e-17 |
| Achromobacter_xylosoxidans_NBRC_15126__1P4H2CBXLAH_Achromobacter_xylosoxidans_NBRC_15126_c | 0.000000 | -0.000000e+00 |
| Achromobacter_xylosoxidans_NBRC_15126__23DHMPO_Achromobacter_xylosoxidans_NBRC_15126_c | 0.000000 | 1.431937e-17 |
| Achromobacter_xylosoxidans_NBRC_15126__23PDE2_Achromobacter_xylosoxidans_NBRC_15126_c | 0.000000 | 0.000000e+00 |
| Achromobacter_xylosoxidans_NBRC_15126__23PDE4_Achromobacter_xylosoxidans_NBRC_15126_c | 0.000000 | 0.000000e+00 |
| ... | ... | ... |
| SK_Veillonella_atypica_ACS_049_V_Sch6_biomass116_ub | 0.562442 | 0.000000e+00 |
| SK_Veillonella_atypica_ACS_049_V_Sch6_to_community_biomass_ub | 0.562442 | 0.000000e+00 |
| f_final | 1.000000 | 0.000000e+00 |
| abundance_reaction | 43.848202 | 1.040834e-16 |
| community_biomass | 43.848202 | 0.000000e+00 |
55176 rows × 2 columns
Quality Checks
One of the quality checks that should be done is to look into all unbalanced reactions (mass and charge) in the entire model. As said before, such reactions should only exist in the case of boundary reactions, such as exchange, sink and source reactions.
[17]:
unbalanced_reactions = com_model_obj.get_unbalanced_reactions()
print(f"{len(unbalanced_reactions)} unbalanced reactions")
print(f"Example reactions:")
for rxn in list(unbalanced_reactions.keys())[:10]:
print(f"{rxn.id}: {unbalanced_reactions[rxn]}")
235 unbalanced reactions
Example reactions:
Achromobacter_xylosoxidans_NBRC_15126_DM_5DRIB_Achromobacter_xylosoxidans_NBRC_15126_c: {'C': -5.0, 'H': -10.0, 'O': -4.0}
Achromobacter_xylosoxidans_NBRC_15126_DM_5MTR_Achromobacter_xylosoxidans_NBRC_15126_c: {'C': -6.0, 'H': -12.0, 'O': -4.0, 'S': -1.0}
Achromobacter_xylosoxidans_NBRC_15126_DM_dhptd_Achromobacter_xylosoxidans_NBRC_15126_c: {'C': -5.0, 'H': -8.0, 'O': -4.0}
Achromobacter_xylosoxidans_NBRC_15126_DM_hcys_L_Achromobacter_xylosoxidans_NBRC_15126_c: {'C': -4.0, 'H': -9.0, 'N': -1.0, 'O': -2.0, 'S': -1.0}
Achromobacter_xylosoxidans_NBRC_15126_EX_biomass_e_Achromobacter_xylosoxidans_NBRC_15126_c: {'X': -1.0}
Achromobacter_xylosoxidans_NBRC_15126_dreplication_Achromobacter_xylosoxidans_NBRC_15126_c: {'X': 1.0}
Achromobacter_xylosoxidans_NBRC_15126_pbiosynthesis_Achromobacter_xylosoxidans_NBRC_15126_c: {'X': 1.0}
Achromobacter_xylosoxidans_NBRC_15126_rtranscription_Achromobacter_xylosoxidans_NBRC_15126_c: {'X': 1.0}
Achromobacter_xylosoxidans_NBRC_15126_biomass489: {'charge': 0.8556250000000518, 'C': -39.34040300000007, 'H': -62.7781865000005, 'N': -8.576429499999936, 'O': -14.310783000000422, 'P': -0.8120575000000315, 'S': -0.222525, 'X': -2.0, 'Co': -0.0030965, 'Ca': -0.0030965, 'Cl': -0.0030965, 'Cu': -0.0030965, 'Fe': -0.012386, 'K': -0.0030965, 'Mg': -0.0030965, 'Mn': -0.0030965, 'Zn': -0.0030965}
Actinomyces_naeslundii_str_Howell_279_DM_5MTR_Actinomyces_naeslundii_str_Howell_279_c: {'C': -6.0, 'H': -12.0, 'O': -4.0, 'S': -1.0}
Analysis of community models
PyCoMo offers the option to calculate all potential exchange metabolites and cross-feeding interactions in a community, independent of the community composition. The example for this part will be a three member community published by Koch et al. 2019 (https://doi.org/10.1371/journal.pcbi.1006759). The three member organisms are representatives of functional guilds in a biogas community.
Creating the community model
We repeat the steps as before.
[18]:
test_model_dir = "../data/use_case/koch"
named_models = pycomo.load_named_models_from_dir(test_model_dir)
'3PG' is not a valid SBML 'SId'.
'2PG' is not a valid SBML 'SId'.
'2PG__PEP' is not a valid SBML 'SId'.
'3PG__2PG' is not a valid SBML 'SId'.
'0Pyr__AcCoA' is not a valid SBML 'SId'.
'3PG' is not a valid SBML 'SId'.
'2PG' is not a valid SBML 'SId'.
'5CHOMPT' is not a valid SBML 'SId'.
'3PG__2PG__3PG' is not a valid SBML 'SId'.
'5CHOMPT__CHH4MPT' is not a valid SBML 'SId'.
'5CHOMPT' is not a valid SBML 'SId'.
'3PG' is not a valid SBML 'SId'.
'2PG' is not a valid SBML 'SId'.
'2PG__3PG' is not a valid SBML 'SId'.
'3PG__DPG' is not a valid SBML 'SId'.
'5CHOMPT__CHH4MPT' is not a valid SBML 'SId'.
[19]:
named_models
[19]:
{'dv': <Model CNA_DV at 0x2cf3e2a9cd0>,
'mb': <Model CNA_MB at 0x2cf3e38b610>,
'mh': <Model CNA_MM at 0x2cf3e38b310>}
[20]:
single_org_models = []
for name, model in named_models.items():
single_org_model = pycomo.SingleOrganismModel(model, name)
single_org_models.append(single_org_model)
community_name = "koch_community_model"
com_model_obj = pycomo.CommunityModel(single_org_models, community_name)
With the community model generated, we set the medium for the analysis, as done by Koch et al.
[21]:
medium = {
'EX_CO2_EX_medium': 1000.0,
'EX_Eth_EX_medium': 1000.0,
'EX_BM_tot_medium': 1000.0
}
com_model_obj.medium = medium
com_model_obj.apply_medium()
# Some metabolites are not allowed to accumulate in the medium.
com_model_obj.model.reactions.get_by_id("EX_Form_EX_medium").upper_bound = 0.
com_model_obj.model.reactions.get_by_id("EX_H2_EX_medium").upper_bound = 0.
2025-11-24 16:11:28,237 - PyCoMo - INFO - No community model generated yet. Generating now:
2025-11-24 16:11:28,254 - PyCoMo - INFO - Identified biomass reaction from objective: r_BMDV2BMc
2025-11-24 16:11:28,404 - PyCoMo - INFO - Identified biomass reaction from objective: BM_Synth
2025-11-24 16:11:28,630 - PyCoMo - INFO - Identified biomass reaction from objective: BM_Synth
2025-11-24 16:11:28,849 - PyCoMo - WARNING - No annotation overlap found for matching several metabolites (8). Please make sure that the matched metabolites are indeed representing the same substance in all models! The list of metaboliteswithout annotation overlap can be accessed via 'model.no_annotation_overlap'
2025-11-24 16:11:28,942 - PyCoMo - WARNING - There are 320 metabolites without elements in the model. Mass balance checks may be unreliable.
2025-11-24 16:11:28,944 - PyCoMo - INFO - Generated community model.
Calculating potential metabolite exchange
All potential exchange metabolite fluxes and cross-feeding interactions can be calculated with the potential_metabolite_exchanges method. This is a single FVA, but with a minimum objective of 0 and relaxed constraints. All reaction constraints are changed to include the value 0, which circumvents cases where a specific flux through a reaction is required, leading to infeasible solutions for certain community compositions.
[22]:
com_model_obj.potential_metabolite_exchanges()
[<Reaction dv_TF_H2_TF_dv_External_Species at 0x2cf3ec65ed0>, <Reaction dv_TF_Ac_TF_dv_External_Species at 0x2cf3ec66fd0>, <Reaction dv_TF_CO2_TF_dv_External_Species at 0x2cf3ec66f50>, <Reaction dv_TF_Form_TF_dv_External_Species at 0x2cf3ec67710>, <Reaction dv_TF_SO4_TF_dv_External_Species at 0x2cf3ec67b50>, <Reaction dv_TF_H2S_TF_dv_External_Species at 0x2cf3ec67f10>, <Reaction dv_TF_Eth_TF_dv_External_Species at 0x2cf3ec67e50>, <Reaction dv_TF_Lac_TF_dv_External_Species at 0x2cf3ec67bd0>, <Reaction dv_TF_Pyr_TF_dv_External_Species at 0x2cf3e2d4890>, <Reaction EX_H2_EX_medium at 0x2cf3ef46e50>, <Reaction EX_Ac_EX_medium at 0x2cf3ef47b90>, <Reaction EX_CO2_EX_medium at 0x2cf3ec82d90>, <Reaction EX_Form_EX_medium at 0x2cf3ec82ed0>, <Reaction EX_SO4_EX_medium at 0x2cf3ec9a410>, <Reaction EX_H2S_EX_medium at 0x2cf3e669f50>, <Reaction EX_Eth_EX_medium at 0x2cf3f0054d0>, <Reaction EX_Lac_EX_medium at 0x2cf3f007a50>, <Reaction EX_Pyr_EX_medium at 0x2cf3f005f10>, <Reaction mb_TF_H2_TF_mb_External_Species at 0x2cf3f672c90>, <Reaction mb_TF_CO2_TF_mb_External_Species at 0x2cf3e518190>, <Reaction mb_TF_CH4_TF_mb_External_Species at 0x2cf3e519490>, <Reaction mb_TF_Ac_TF_mb_External_Species at 0x2cf3e528590>, <Reaction mb_TF_MetOH_TF_mb_External_Species at 0x2cf3e528610>, <Reaction mb_TF_BM_tot_mb_External_Species at 0x2cf3e528910>, <Reaction EX_CH4_EX_medium at 0x2cf3e5d9d10>, <Reaction EX_MetOH_EX_medium at 0x2cf3e5eced0>, <Reaction EX_BM_tot_medium at 0x2cf3e5ed410>, <Reaction mh_TF_H2_TF_mh_External_Species at 0x2cf3ea8edd0>, <Reaction mh_TF_CO2_TF_mh_External_Species at 0x2cf3ef62010>, <Reaction mh_TF_CH4_TF_mh_External_Species at 0x2cf3ef61f50>, <Reaction mh_TF_Form_TF_mh_External_Species at 0x2cf3ef62790>, <Reaction mh_TF_BM_tot_mh_External_Species at 0x2cf3ef62e50>]
2025-11-24 16:11:35,711 - PyCoMo - INFO - worker 10632: Loop correction will be applied on dv_TF_H2_TF_dv_External_Species
2025-11-24 16:11:35,712 - PyCoMo - INFO - worker 6876: Loop correction will be applied on dv_TF_Ac_TF_dv_External_Species
2025-11-24 16:11:35,713 - PyCoMo - INFO - worker 34716: Loop correction will be applied on dv_TF_CO2_TF_dv_External_Species
2025-11-24 16:11:35,714 - PyCoMo - INFO - worker 2112: Loop correction will be applied on dv_TF_Form_TF_dv_External_Species
2025-11-24 16:11:35,715 - PyCoMo - INFO - worker 33956: Loop correction will be applied on dv_TF_SO4_TF_dv_External_Species
2025-11-24 16:11:35,717 - PyCoMo - INFO - worker 12248: Loop correction will be applied on dv_TF_H2S_TF_dv_External_Species
2025-11-24 16:11:35,719 - PyCoMo - INFO - worker 30288: Loop correction will be applied on dv_TF_Eth_TF_dv_External_Species
2025-11-24 16:11:35,721 - PyCoMo - INFO - worker 31876: Loop correction will be applied on dv_TF_Lac_TF_dv_External_Species
2025-11-24 16:11:35,722 - PyCoMo - INFO - worker 32016: Loop correction will be applied on dv_TF_Pyr_TF_dv_External_Species
2025-11-24 16:11:35,731 - PyCoMo - INFO - worker 19556: Loop correction will be applied on mb_TF_H2_TF_mb_External_Species
2025-11-24 16:11:35,732 - PyCoMo - INFO - worker 29876: Loop correction will be applied on mb_TF_CO2_TF_mb_External_Species
2025-11-24 16:11:35,734 - PyCoMo - INFO - worker 31252: Loop correction will be applied on mb_TF_CH4_TF_mb_External_Species
2025-11-24 16:11:35,735 - PyCoMo - INFO - worker 23180: Loop correction will be applied on mb_TF_Ac_TF_mb_External_Species
2025-11-24 16:11:35,737 - PyCoMo - INFO - worker 27616: Loop correction will be applied on mb_TF_MetOH_TF_mb_External_Species
2025-11-24 16:11:35,738 - PyCoMo - INFO - worker 32216: Loop correction will be applied on mb_TF_BM_tot_mb_External_Species
2025-11-24 16:11:35,753 - PyCoMo - INFO - worker 12248: Loop correction will be applied on mh_TF_H2_TF_mh_External_Species
2025-11-24 16:11:35,755 - PyCoMo - INFO - worker 2112: Loop correction will be applied on mh_TF_CO2_TF_mh_External_Species
2025-11-24 16:11:35,756 - PyCoMo - INFO - worker 32216: Loop correction will be applied on mh_TF_CH4_TF_mh_External_Species
2025-11-24 16:11:35,758 - PyCoMo - INFO - worker 6876: Loop correction will be applied on mh_TF_Form_TF_mh_External_Species
2025-11-24 16:11:35,761 - PyCoMo - INFO - worker 31876: Loop correction will be applied on mh_TF_BM_tot_mh_External_Species
2025-11-24 16:11:35,814 - PyCoMo - INFO - Processed 100.0% of fva steps
[22]:
| metabolite_id | metabolite_name | cross_feeding | produced_by | consumed_by | |
|---|---|---|---|---|---|
| 0 | H2_EX_medium | H2_external | True | [dv] | [mb, mh] |
| 1 | Ac_EX_medium | acetate_external | True | [dv] | [mb] |
| 2 | CO2_EX_medium | CO2_external | True | [mb, mh] | [dv, mb, mh] |
| 3 | Form_EX_medium | formate_external | True | [dv] | [mh] |
| 4 | SO4_EX_medium | sulfate_external | False | [] | [] |
| 5 | H2S_EX_medium | hydrogensulfide_external | False | [] | [] |
| 6 | Eth_EX_medium | ethanol_external | False | [] | [dv] |
| 7 | Lac_EX_medium | lactate_external | False | [] | [] |
| 8 | Pyr_EX_medium | pyruvate_external | False | [] | [] |
| 9 | CH4_EX_medium | nethane_external | False | [mb, mh] | [] |
| 10 | MetOH_EX_medium | nethanol_external | False | [] | [] |
| 11 | BM_tot_medium | total_biomass | False | [] | [] |
Plotting the maxiumum growth rate over the composition space
[23]:
import pandas as pd
# Iterate over the fractions in steps of 0.01
com_model_obj.convert_to_fixed_abundance()
rows = []
for i in range (0,100,1): # fraction of D. vulgaris
for j in range (0, 100-i, 1): # fraction of M. hungatei
if (100-i-j) < 0:
continue
abundances = {"dv": i/100., "mh": j/100., "mb": (100-i-j)/100.}
# Apply the abuyndances
com_model_obj.apply_fixed_abundance(abundances)
# Reapply the bound restrictions of the exchange reactions
com_model_obj.model.reactions.get_by_id("EX_Form_EX_medium").upper_bound = 0.
com_model_obj.model.reactions.get_by_id("EX_H2_EX_medium").upper_bound = 0.
# Calculate the optimal growth rate
solution = com_model_obj.model.optimize()
growth = 0. if str(solution.status) == "infeasible" else solution.objective_value
rows.append({"dv": i/100., "mh": j/100., "growth": growth})
growth_df = pd.DataFrame(rows)
[24]:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()
# Restructure dataframe for heatmap
growth_df_pivot = growth_df.pivot(index="mh", columns="dv", values="growth")
# Draw a heatmap with the numeric values in each cell
f, ax = plt.subplots(figsize=(9, 6))
sns.heatmap(growth_df_pivot, ax=ax)
ax.invert_yaxis()
[ ]: