2. CBMPy Quick Start Guide

Before delving into the modeling of microbial communities, let’s establish a solid foundation by exploring the core principles of the CBMPy package. We will guide you through a series of instructive examples that illuminate key operations for GSMM’s. These examples will demonstrate the foundational techniques for loading and manipulating models. For these examples we will use the E. coli core iJR904 which comes with the CBMPy package. Through these hands-on demonstrations, you’ll swiftly grasp the fundamental operations that underpin effective model manipulation. For a more comprehensive understanding and explanation of all the functionalities available in CBMPy, we recommend you to read the extensive documentation.

For those who have prior experience with COBRApy, the transition to CBMPy will feel remarkably intuitive, as the two share notable similarities in their approach and methodology.

2.1. Loading a model using CBMPy

To load a model and perform a simple FBA analysis on it type:

import cbmpy
from cbmpy.CBModel import Model

iJR904: Model = cbmpy.readSBML3FBC("cbmpy_test_ecoli") #Load the model
solution = cbmpy.doFBA(iJR904) #Perform FBA, returns the objective value
FBAsol = iJR904.getSolutionVector(names=True) #Get all reaction ids with there flux value

Here model iJR904 refers to a cbmpy.CBModel which represents the GSMM of the loaded organism .

2.2. SBML and COBRA models

The cbmpy.loadModel() function is designed to efficiently handle a wide range of models. It seamlessly supports the import of models encoded in the standardized Systems Biology Markup Language (SBML) format, as well as models exported by COBRApy. This means that you can easily work with different versions of SBML and COBRApy models without having to specify them explicitly. This flexibility simplifies the model loading process.

Note

Sometimes the conversion of exchanges, sinks or other boundary conditions are not properly set when exporting or importing a COBRA model into CBMPy therefore always check if these reactions are set correctly in the loaded model.

2.3. Saving a model

There are two ways to save a cbmpy model. The easiest way is to save your altered model to the latest version of SBML:

from cbmpy.CBModel import Reaction

reaction: Reaction = iJR904.getReaction("R_EX_glc__D_e") #Get a reaction from the model
print(reaction.getLowerBound()) #-10.0
reaction.setLowerBound(0) #Alter the reaction in the model
print(reaction.getLowerBound()) #0.0

cbmpy.saveModel(iJR904, "adjusted_model.xml") #Save the new model to a XML file

You can save the modified model in a file format of your choice using any of the following methods:

cbmpy.writeCOBRASBML(...)
cbmpy.writeModelToExcel97(...)
cbmpy.writeSBML3FBCV2(...)

2.4. Reactions, Reagents and Species

In CBMPy, the cbmpy.CBModel object stores the model and all its attributes. When working with the model, most modifications will involve manipulating this object. In the previous section, we demonstrated how to load the E. coli core iJR904 model and perform a FBA on it. Now, let’s explore some basic alterations that can be made to the model.

Reactions

To list all the reactions in the model, or list the reaction containing a certain string you can call the following functions:

modelRxns = iJR904.getReactionIds() #All the reactions, as a list[str]
print(modelRxns)

print(iJR904.getReactionIds('PG'))  #Outputs only reactions with "PG" in their ID

Once you have identified your reaction of interest, you can easily access its key details, including the reagents, upper and lower bounds, and equation, as follows:

from cbmpy.CBModel import Reagent, Species

reaction: Reaction = iJR904.getReaction("R_PGK")

reagents: list[Reagent] = reaction.getReagentObjIds()  # Get all reagent ids of the reaction
print(reagents)

bounds = [reaction.getLowerBound(), reaction.getUpperBound()] # Get the lower and upper bound
print(bounds)

equation = reaction.getEquation() # Get the reactions equation
print(equation)

Furthermore you can check if a reaction is reversible and if it is an exchange reaction:

print(reaction.is_exchange) #True if the reaction is an exchange reaction

print(reaction.reversible) #True if the reaction is reversible

You can easily add your own defined reactions to the model using the createReaction() method, if we for example want to add the irreversible reaction: ATP + H2O -> ADP + Pi + H we can do this with the following code:

iJR904.createReaction('ATPsink', reversible = False) # Create a new empty irreversible reaction

# Add the reagents to the reaction, All metabolites already existed in the model so we did not
# Need to create them
iJR904.createReactionReagent('ATPsink', metabolite = "M_atp_c" , coefficient = -1.0)
iJR904.createReactionReagent('ATPsink', metabolite =  "M_h2o_c", coefficient = -1.0)
iJR904.createReactionReagent('ATPsink', metabolite = "M_adp_c", coefficient = 1.0)
iJR904.createReactionReagent('ATPsink', metabolite = "M_pi_c" , coefficient = 1.0)
iJR904.createReactionReagent('ATPsink', metabolite =  "M_h_c", coefficient = 1.0)

Reagents

The Reagent class represents a reagent within a reaction, providing essential information about its properties and characteristics. Within the class, users can access and manipulate the reagents associated with a specific reaction within the model. The reagent itself is linked to a Species which we will cover shortly. You can access a reagent by retrieving it from an instance of the Reaction class, given the R_PGK reaction from the previous example we can access information about a reagent as follows:

reagent: Reagent = reaction.getReagent("R_PGK_M_3pg_c")

reagent.getCoefficient() # Get the reagent's stoichiometric coefficient

reagent.getCompartmentId() #Get the compartment

reagent.getSpecies() # Get the species id corresponding to this reagent

If a reagent has a negative coefficient it is consumed by the reaction, if the reagent has a positive coefficient it is created by the reaction.

Species

Species represent the metabolites in the system using the Species object you can easily retrieve details such as the molecular formula, charge, and the compartment of the species. Furthermore you can list the reactions in which a species is consumed or synthesized

species: Species = iJR904.getSpecies("M_pi_c")

species.getChemFormula()
species.getCharge()
species.getCompartmentId() # Gives the id of the compartment in which the species lives
species.isReagentOf() # Returns a list of reaction ids in which the species is present

Objective function

To perform FBA on the model you need to set an objective function. The output of FBA will be a flux distribution which minimizes/maximizes this objective function.

To check what the active objective function of the model is you can write:

objective_ids = iJR904.getActiveObjectiveReactionIds() #Returns the IDs of the reactions which have been set as objective reaction

print(objective_ids)
#['R_BIOMASS_Ecoli']

objective = iJR904.getActiveObjective()
print(objective.getOperation())
#Maximize

reaction: Reaction = iJR904.getReaction("R_EX_glc__D_e")
reaction.setLowerBound(-10) #Reset lower bound
solution = cbmpy.doFBA(iJR904) #0.922

Calling cbmpy.doFBA(iJR904) will calculate the fluxes such that the flux through the reaction with id R_BIOMASS_Ecoli is maximized.

Next, we’ll delve into dynamic modeling of CBMPy models. Once we lay this foundation, we’ll journey into the fascinating realm of modeling microbial communities.