<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Getting Started
Loading a model and inspecting it
To begin with, cobrapy comes with bundled models for Salmonella and E. coli, as well as a "textbook" model of E. coli core metabolism. To load a test model, type
Step1:  The reactions, metabolites, and genes attributes of the cobrapy model are a special type of list called a cobra.DictList, and each one is made up of cobra.Reaction, cobra.Metabolite and cobra.Gene objects respectively.
Step2:  When using Jupyter notebook this type of information is rendered as a table.
Step3:  Just like a regular list, objects in the DictList can be retrieved by index. For example, to get the 30th reaction in the model (at index 29 because of 0-indexing)
Step4:  Additionally, items can be retrieved by their id using the DictList.get_by_id() function. For example, to get the cytosolic atp metabolite object (the id is "atp_c"), we can do the following
Step5:  As an added bonus, users with an interactive shell such as IPython will be able to tab-complete to list elements inside a list. While this is not recommended behavior for most code because of the possibility for characters like "-" inside ids, this is very useful while in an interactive prompt
Step6:  Reactions
We will consider the reaction glucose 6-phosphate isomerase, which interconverts glucose 6-phosphate and fructose 6-phosphate. The reaction id for this reaction in our test model is PGI.
Step7:  We can view the full name and reaction catalyzed as strings
Step8:  We can also view reaction upper and lower bounds. Because the pgi.lower_bound < 0, and pgi.upper_bound > 0, pgi is reversible.
Step9:  We can also ensure the reaction is mass balanced. This function will return elements which violate mass balance. If it comes back empty, then the reaction is mass balanced.
Step10:  In order to add a metabolite, we pass in a dict with the metabolite object and its coefficient
Step11:  The reaction is no longer mass balanced
Step12:  We can remove the metabolite, and the reaction will be balanced once again.
Step13:  It is also possible to build the reaction from a string. However, care must be taken when doing this to ensure reaction id's match those in the model. The direction of the arrow is also used to update the upper and lower bounds.
Step14:  Metabolites
We will consider cytosolic atp as our metabolite, which has the id "atp_c" in our test model.
Step15:  We can print out the metabolite name and compartment (cytosol in this case) directly as string.
Step16:  We can see that ATP is a charged molecule in our model.
Step17:  We can see the chemical formula for the metabolite as well.
Step18:  The reactions attribute gives a frozenset of all reactions using the given metabolite. We can use this to count the number of reactions which use atp.
Step19:  A metabolite like glucose 6-phosphate will participate in fewer reactions.
Step20:  Genes
The gene_reaction_rule is a boolean representation of the gene requirements for this reaction to be active as described in Schellenberger et al 2011 Nature Protocols 6(9)
Step21:  Corresponding gene objects also exist. These objects are tracked by the reactions itself, as well as by the model
Step22:  Each gene keeps track of the reactions it catalyzes
Step23:  Altering the gene_reaction_rule will create new gene objects if necessary and update all relationships.
Step24:  Newly created genes are also added to the model
Step25:  The delete_model_genes function will evaluate the GPR and set the upper and lower bounds to 0 if the reaction is knocked out. This function can preserve existing deletions or reset them using the cumulative_deletions flag.
Step26:  The undelete_model_genes can be used to reset a gene deletion
Step27:  Making changes reversibly using models as contexts
Quite often, one wants to make small changes to a model and evaluate the impacts of these. For example, we may want to knock-out all reactions sequentially, and see what the impact of this is on the objective function. One way of doing this would be to create a new copy of the model before each knock-out with model.copy(). However, even with small models, this is a very slow approach as models are quite complex objects. Better then would be to do the knock-out, optimizing and then manually resetting the reaction bounds before proceeding with the next reaction. Since this is such a common scenario however, cobrapy allows us to use the model as a context, to have changes reverted automatically.
Step28:  If we look at those knocked reactions, see that their bounds have all been reverted.
Step29:  Nested contexts are also supported
Step30:  Most methods that modify the model are supported like this including adding and removing reactions and metabolites and setting the objective. Supported methods and functions mention this in the corresponding documentation.
While it does not have any actual effect, for syntactic convenience it is also possible to refer to the model by a different name than outside the context. Such as
<ASSISTANT_TASK:>
Python Code:
from __future__ import print_function
import cobra
import cobra.test
# "ecoli" and "salmonella" are also valid arguments
model = cobra.test.create_test_model("textbook")
Explanation: Getting Started
Loading a model and inspecting it
To begin with, cobrapy comes with bundled models for Salmonella and E. coli, as well as a "textbook" model of E. coli core metabolism. To load a test model, type
End of explanation
print(len(model.reactions))
print(len(model.metabolites))
print(len(model.genes))
Explanation: The reactions, metabolites, and genes attributes of the cobrapy model are a special type of list called a cobra.DictList, and each one is made up of cobra.Reaction, cobra.Metabolite and cobra.Gene objects respectively.
End of explanation
model
Explanation: When using Jupyter notebook this type of information is rendered as a table.
End of explanation
model.reactions[29]
Explanation: Just like a regular list, objects in the DictList can be retrieved by index. For example, to get the 30th reaction in the model (at index 29 because of 0-indexing):
End of explanation
model.metabolites.get_by_id("atp_c")
Explanation: Additionally, items can be retrieved by their id using the DictList.get_by_id() function. For example, to get the cytosolic atp metabolite object (the id is "atp_c"), we can do the following:
End of explanation
model.reactions.EX_glc__D_e.bounds
Explanation: As an added bonus, users with an interactive shell such as IPython will be able to tab-complete to list elements inside a list. While this is not recommended behavior for most code because of the possibility for characters like "-" inside ids, this is very useful while in an interactive prompt:
End of explanation
pgi = model.reactions.get_by_id("PGI")
pgi
Explanation: Reactions
We will consider the reaction glucose 6-phosphate isomerase, which interconverts glucose 6-phosphate and fructose 6-phosphate. The reaction id for this reaction in our test model is PGI.
End of explanation
print(pgi.name)
print(pgi.reaction)
Explanation: We can view the full name and reaction catalyzed as strings
End of explanation
print(pgi.lower_bound, "< pgi <", pgi.upper_bound)
print(pgi.reversibility)
Explanation: We can also view reaction upper and lower bounds. Because the pgi.lower_bound < 0, and pgi.upper_bound > 0, pgi is reversible.
End of explanation
pgi.check_mass_balance()
Explanation: We can also ensure the reaction is mass balanced. This function will return elements which violate mass balance. If it comes back empty, then the reaction is mass balanced.
End of explanation
pgi.add_metabolites({model.metabolites.get_by_id("h_c"): -1})
pgi.reaction
Explanation: In order to add a metabolite, we pass in a dict with the metabolite object and its coefficient
End of explanation
pgi.check_mass_balance()
Explanation: The reaction is no longer mass balanced
End of explanation
pgi.subtract_metabolites({model.metabolites.get_by_id("h_c"): -1})
print(pgi.reaction)
print(pgi.check_mass_balance())
Explanation: We can remove the metabolite, and the reaction will be balanced once again.
End of explanation
pgi.reaction = "g6p_c --> f6p_c + h_c + green_eggs + ham"
pgi.reaction
pgi.reaction = "g6p_c <=> f6p_c"
pgi.reaction
Explanation: It is also possible to build the reaction from a string. However, care must be taken when doing this to ensure reaction id's match those in the model. The direction of the arrow is also used to update the upper and lower bounds.
End of explanation
atp = model.metabolites.get_by_id("atp_c")
atp
Explanation: Metabolites
We will consider cytosolic atp as our metabolite, which has the id "atp_c" in our test model.
End of explanation
print(atp.name)
print(atp.compartment)
Explanation: We can print out the metabolite name and compartment (cytosol in this case) directly as string.
End of explanation
atp.charge
Explanation: We can see that ATP is a charged molecule in our model.
End of explanation
print(atp.formula)
Explanation: We can see the chemical formula for the metabolite as well.
End of explanation
len(atp.reactions)
Explanation: The reactions attribute gives a frozenset of all reactions using the given metabolite. We can use this to count the number of reactions which use atp.
End of explanation
model.metabolites.get_by_id("g6p_c").reactions
Explanation: A metabolite like glucose 6-phosphate will participate in fewer reactions.
End of explanation
gpr = pgi.gene_reaction_rule
gpr
Explanation: Genes
The gene_reaction_rule is a boolean representation of the gene requirements for this reaction to be active as described in Schellenberger et al 2011 Nature Protocols 6(9):1290-307.
The GPR is stored as the gene_reaction_rule for a Reaction object as a string.
End of explanation
pgi.genes
pgi_gene = model.genes.get_by_id("b4025")
pgi_gene
Explanation: Corresponding gene objects also exist. These objects are tracked by the reactions itself, as well as by the model
End of explanation
pgi_gene.reactions
Explanation: Each gene keeps track of the reactions it catalyzes
End of explanation
pgi.gene_reaction_rule = "(spam or eggs)"
pgi.genes
pgi_gene.reactions
Explanation: Altering the gene_reaction_rule will create new gene objects if necessary and update all relationships.
End of explanation
model.genes.get_by_id("spam")
Explanation: Newly created genes are also added to the model
End of explanation
cobra.manipulation.delete_model_genes(
    model, ["spam"], cumulative_deletions=True)
print("after 1 KO: %4d < flux_PGI < %4d" % (pgi.lower_bound, pgi.upper_bound))
cobra.manipulation.delete_model_genes(
    model, ["eggs"], cumulative_deletions=True)
print("after 2 KO:  %4d < flux_PGI < %4d" % (pgi.lower_bound, pgi.upper_bound))
Explanation: The delete_model_genes function will evaluate the GPR and set the upper and lower bounds to 0 if the reaction is knocked out. This function can preserve existing deletions or reset them using the cumulative_deletions flag.
End of explanation
cobra.manipulation.undelete_model_genes(model)
print(pgi.lower_bound, "< pgi <", pgi.upper_bound)
Explanation: The undelete_model_genes can be used to reset a gene deletion
End of explanation
model = cobra.test.create_test_model('textbook')
for reaction in model.reactions[:5]:
    with model as model:
        reaction.knock_out()
        model.optimize()
        print('%s blocked (bounds: %s), new growth rate %f' %
              (reaction.id, str(reaction.bounds), model.objective.value))
Explanation: Making changes reversibly using models as contexts
Quite often, one wants to make small changes to a model and evaluate the impacts of these. For example, we may want to knock-out all reactions sequentially, and see what the impact of this is on the objective function. One way of doing this would be to create a new copy of the model before each knock-out with model.copy(). However, even with small models, this is a very slow approach as models are quite complex objects. Better then would be to do the knock-out, optimizing and then manually resetting the reaction bounds before proceeding with the next reaction. Since this is such a common scenario however, cobrapy allows us to use the model as a context, to have changes reverted automatically.
End of explanation
[reaction.bounds for reaction in model.reactions[:5]]
Explanation: If we look at those knocked reactions, see that their bounds have all been reverted.
End of explanation
print('original objective: ', model.objective.expression)
with model:
    model.objective = 'ATPM'
    print('print objective in first context:', model.objective.expression)
    with model:
        model.objective = 'ACALD'
        print('print objective in second context:', model.objective.expression)
    print('objective after exiting second context:',
          model.objective.expression)
print('back to original objective:', model.objective.expression)
Explanation: Nested contexts are also supported
End of explanation
with model as inner:
    inner.reactions.PFK.knock_out
Explanation: Most methods that modify the model are supported like this including adding and removing reactions and metabolites and setting the objective. Supported methods and functions mention this in the corresponding documentation.
While it does not have any actual effect, for syntactic convenience it is also possible to refer to the model by a different name than outside the context. Such as
End of explanation
<END_TASK>