#cobra.core.Model.py
#TODO: Improve copy time. Perhaps use references for metabolites in
#reactions.
#Here we're dealing with the fact that numpy isn't supported in jython
#and we've made some numjy modules that use the cern.colt matrices to
#mimic the used numpy behavior.
from warnings import warn
from copy import deepcopy
from ..solvers import optimize
from .Object import Object
from .Reaction import Reaction
from .Metabolite import Metabolite
from .Formula import Formula
from .DictList import DictList
#*********************************************************************************
#
#TODO: Implement self.reactions[:]._boundary and use
# Note, there are some issues with using a gene as opposed to a protein in the
#nomenclature; this will be addressed after the first iteration of cleaning.
#
# Note, when a reaction is added to the Model it will no longer keep personal
#instances of it's Metabolites, it will reference Model.metabolites to improve
#performance. When doing this, take care to monitor the metabolite coefficients.
#Do the same for Model.reactions[:].genes and Model.genes
#
#*********************************************************************************
#######################
#BEGIN Class Model
#
[docs]class Model(Object):
"""Model is a class for analyzing metabolic models with
the COBRA toolbox developed in the Palsson Lab at UCSD. Make
all of the objects (Reaction, Metabolite, ...) to make OOP easier.
"""
def __setstate__(self, state):
"""Make sure all cobra.Objects in the model point to the model
TODO: Make sure that the genes and metabolites referenced by
the reactions.(genes|metabolites) point to the model's genes
and metabolites.
"""
self.__dict__.update(state)
[[setattr(x, '_model', self)
for x in self.__dict__[y]]
for y in ['reactions', 'genes', 'metabolites']]
def __init__(self, description=None):
if isinstance(description, Model):
self.__dict__ = description.__dict__
else:
Object.__init__(self, description)
self.description = self.id
self._trimmed = False #This might get changed to a dict of
#gene:[reactions in which the gene participates]
self._trimmed_genes = None #This will be integrated with _trimmed
self._trimmed_reactions = None #as will this
self.legacy_format = False #DEPRECATED
#Allow the creation of an empty object which will facilitate development
#of SBML parsers and other development issues.
self.genes = DictList()
self.reactions = DictList() #A list of cobra.Reactions
self.metabolites = DictList() #A list of cobra.Metabolites
#genes based on their ids {Gene.id: Gene}
self.compartments = {}
def __add__(self, other_model):
"""Adds two models. +
The issue of reactions being able to exists in multiple Models now arises, the same
for metabolites and such. This might be a little difficult as a reaction with the
same name / id in two models might have different coefficients for their metabolites
due to pH and whatnot making them different reactions.
"""
new_model = self.copy()
new_reactions = deepcopy(other_model.reactions)
new_model.add_reactions(new_reactions)
new_model.id = self.id + '_' + other_model.id
return new_model
def __iadd__(self, other_model):
"""Adds a Model to this model +=
The issue of reactions being able to exists in multiple Models now arises, the same
for metabolites and such. This might be a little difficult as a reaction with the
same name / id in two models might have different coefficients for their metabolites
due to pH and whatnot making them different reactions.
"""
new_reactions = deepcopy(other_model.reactions)
self.add_reactions(new_reactions)
self.id = self.id + '_' + other_model.id
return self
[docs] def copy(self, print_time=False):
"""Provides a partial 'deepcopy' of the Model. All of the Metabolite, Gene,
and Reaction objects are created anew but in a faster fashion than deepcopy
print_time: Boolean used for debugging
"""
the_copy = Object.guided_copy(self)
the_copy.metabolites = None
the_copy.reactions = None
the_copy.compartments = deepcopy(self.compartments)
if print_time:
from time import time
start_time = time()
the_metabolites = DictList([x.guided_copy(the_copy)
for x in self.metabolites])
if print_time:
print 'Metabolite guided copy: %1.4f'%(time() - start_time)
start_time = time()
the_genes = DictList([x.guided_copy(the_copy)
for x in self.genes])
if print_time:
print 'Gene guided copy: %1.4f'%(time() - start_time)
start_time = time()
#TODO: See if we can use the DictList objects instead
metabolite_dict = dict([(k.id, k)
for k in the_metabolites])
gene_dict = dict([(k.id, k)
for k in the_genes])
the_reactions = DictList([x.guided_copy(the_copy, the_metabolites._object_dict,
the_genes._object_dict)
for x in self.reactions])
if print_time:
print 'Reaction guided copy: %1.4f'%(time() - start_time)
the_copy.reactions = the_reactions
the_copy.genes = the_genes
the_copy.metabolites = the_metabolites
return the_copy
def _update_reaction(self, reaction):
"""Updates everything associated with the reaction.id of reaction.
reaction: A cobra.Reaction object, or a list of these objects.
"""
warn("WARNING: To be modified. It will be faster to use properties of the DictList " +\
"self.reactions to find a reaction and update the matrices " +\
"This function is only used after the Model has been " +\
"converted to matrices. It is typically faster to access the objects" +\
"in the Model directly. This function will eventually moved to another" +\
"module for advanced users due to the potential for mistakes.")
if not hasattr(reaction, '__iter__'):
reaction = [reaction]
for the_reaction in reaction:
if the_reaction.id not in self.reactions:
print the_reaction.id + ' is not in the model\n'
continue
reaction_index = self.reactions.index(the_reaction.id)
self.reactions[reaction_index] = the_reaction
[docs] def update(self):
"""Non functional. Model.update is moved to ArrayBasedModel. Please use
the to_array_based_model property to create an ArrayBasedModel.
"""
raise Exception("Model.update is moved to ArrayBasedModel. Please use \n"
"the to_array_based_model property to create an ArrayBasedModel.")
[docs] def add_reaction(self, reaction):
"""Will add a cobra.Reaction object to the model, if
reaction.id is not in self.reactions.
reaction: A :class:`~cobra.core.Reaction` object
"""
self.add_reactions(reaction)
[docs] def add_reactions(self, reaction_list):
"""Will add a cobra.Reaction object to the model, if
reaction.id is not in self.reactions.
reaction_list: A :class:`~cobra.core.Reaction` object or a list of them
"""
#Only add the reaction if one with the same ID is not already
#present in the model.
if type(reaction_list) not in [tuple, list, set, DictList]:
reaction_list = [reaction_list]
#TODO: Use the DictList properties
reactions_in_model = set([x.id
for x in reaction_list]).intersection([x.id
for x in self.reactions])
if len(reactions_in_model) > 0:
print '%i of %i reaction(s) %s already in the model'%(len(reactions_in_model),
len(reaction_list), repr(reactions_in_model))
return
#TODO: Consider using DictList's here, just make sure that the items get appended
#to self.metabolites, self.genes
metabolite_dict = {}
gene_dict = {}
[metabolite_dict.update(dict([(y.id, y) for y in x._metabolites]))
for x in reaction_list]
new_metabolites = [metabolite_dict[x]
for x in set(metabolite_dict).difference(self.metabolites._dict)]
if new_metabolites:
self.add_metabolites(new_metabolites)
[gene_dict.update(dict([(y.id, y) for y in x._genes]))
for x in reaction_list]
new_genes = [gene_dict[x]
for x in set(gene_dict).difference(self.genes._dict)]
if new_genes:
self.genes += DictList(new_genes)
[setattr(x, '_model', self)
for x in new_genes]
#This might slow down performance
#Make sure each reaction knows that it is now part of a Model and uses
#metabolites in the Model and genes in the Model
for the_reaction in reaction_list:
the_reaction._model = self
the_reaction._metabolites = dict([(self.metabolites.get_by_id(k.id), v)
for k, v in the_reaction._metabolites.items()])
the_reaction._genes = dict([(self.genes.get_by_id(k.id), v)
for k, v in the_reaction._genes.items()])
#Make sure the metabolites and genes are aware of the reaction
the_reaction._update_awareness()
#Add the reactions to the Model
self.reactions += reaction_list
[docs] def to_array_based_model(self, deepcopy_model=False):
"""Makes a :class:`~cobra.core.ArrayBasedModel` from a cobra.Model which
may be used to perform linear algebra operations with the
stoichiomatric matrix.
deepcopy_model: Boolean. If False then the ArrayBasedModel points
to the Model
"""
from .ArrayBasedModel import ArrayBasedModel
return ArrayBasedModel(self, deepcopy_model=deepcopy_model)
[docs] def optimize(self, new_objective=None, objective_sense='maximize',
the_problem=None, solver='glpk',
error_reporting=None, quadratic_component=None,
tolerance_optimality=1e-6, tolerance_feasibility=1e-6,
tolerance_barrier=1e-10, **kwargs):
"""Optimize self for self._objective_coefficients or new_objective.
NOTE: Only the most commonly used parameters are presented here. Additional
parameters for cobra.solvers may be available and specified with the
appropriate keyword=value.
new_objective: Reaction, String, or Integer referring to a reaction in
cobra_model.reactions to set as the objective. Currently, only supports single
objective coeffients. Will expand to include mixed objectives.
objective_sense: 'maximize' or 'minimize'
the_problem: None or a problem object for the specific solver that can be used to hot
start the next solution.
solver: 'glpk', 'gurobi', or 'cplex'
error_reporting: None or True to disable or enable printing errors encountered
when trying to find the optimal solution.
quadratic_component: None or
scipy.sparse.dok of dim(len(cobra_model.reactions),len(cobra_model.reactions))
If not None:
Solves quadratic programming problems for cobra_models of the form:
cobra_model = ArrayBasedModel(cobra_model)
minimize: 0.5 * x' * quadratic_component * x + cobra_model._objective_coefficients' * x
such that,
cobra_model._lower_bounds <= x <= cobra_model._upper_bounds
cobra_model._S * x (cobra_model._constraint_sense) cobra_model._b
#See cobra.flux_analysis.solvers for more info on the following parameters. Also,
refer to your solver's manual
tolerance_optimality: Solver tolerance for optimality.
tolerance_feasibility: Solver tolerance for feasibility.
tolerance_barrier: Solver tolerance for barrier method
lp_method: Solver method to solve the problem
#End solver parameters
**kwargs: See additional parameters for your specific solver module in
cobra.solvers
"""
the_solution = optimize(self, solver=solver, new_objective=new_objective,
objective_sense=objective_sense,
the_problem=the_problem,
error_reporting=error_reporting,
quadratic_component=quadratic_component,
tolerance_optimality=tolerance_optimality,
tolerance_feasibility=tolerance_feasibility,
tolerance_barrier=tolerance_barrier,
**kwargs)
return the_solution
def _update_metabolite_formula(self, metabolite_name, metabolite_formula):
"""Associate metabolite_formula with all self.metabolite_names that
match metabolite_name.
metabolite_name: A string from self.metabolite_names
metabolite_formula: A string specifying the chemical formula for
metabolite_name.
TODO: This should be moved to a separate module
"""
if not isinstance(the_formula, Formula):
the_formula = Formula(the_formula)
for the_metabolite in self.metabolites:
if the_metabolite.name == metabolite_name:
the_metabolite.formula = the_formula
[docs] def remove_reactions(self, the_reactions):
"""
the_reactions: instance or list of cobra.Reactions or strings of
self.reactions[:].id.
"""
if not hasattr(the_reactions, '__iter__') or \
hasattr(the_reactions, 'id'):
the_reactions = [the_reactions]
if hasattr(the_reactions[0], 'id'):
the_reactions = [x.id for x in the_reactions]
reactions_to_delete = []
for the_reaction in the_reactions:
try:
the_reaction = self.reactions[self.reactions.index(the_reaction)]
the_reaction.remove_from_model(self)
except:
print '%s not in %s'%(the_reaction, self)
#
#END Class Model
#####################