def _apply_min_growth(community, min_growth, atol=1e-6, rtol=1e-6): """Set minimum growth constraints on a model. Will integrate with the context. """ context = get_context(community) def reset(taxon, lb): logger.info("resetting growth rate constraint for %s" % taxon) community.constraints["objective_" + taxon].ub = None community.constraints["objective_" + taxon].lb = lb for sp in community.taxa: logger.info("setting growth rate constraint for %s" % sp) obj = community.constraints["objective_" + sp] if context: context(partial(reset, sp, obj.lb)) if min_growth[sp] > atol: obj.lb = (1.0 - rtol) * min_growth[sp] - atol else: logger.info( "minimal growth rate smaller than tolerance," " setting to zero." ) obj.lb = 0
def add_cons_vars_to_problem( model: "Model", what: Union[List[CONS_VARS], Tuple[CONS_VARS], Components], **kwargs, ) -> None: """Add variables and constraints to a model's solver object. Useful for variables and constraints that can not be expressed with reactions and lower/upper bounds. It will integrate with the model's context manager in order to revert changes upon leaving the context. Parameters ---------- model : cobra.Model The model to which to add the variables and constraints. what : list or tuple of optlang.interface.Variable or optlang.interface.Constraint The variables and constraints to add to the model. **kwargs : keyword arguments Keyword arguments passed to solver's add() method. """ model.solver.add(what, **kwargs) context = get_context(model) if context: context(partial(model.solver.remove, what))
def add_proteins(self, protein_list: Iterator[Protein]): """Add proteins to the model, in the same fashion as `.add_metabollites`.""" if not hasattr(protein_list, "__iter__"): protein_list = [protein_list] if len(protein_list) == 0: return None # Take left difference pruned = [x for x in protein_list if x.id not in self.proteins] for prot in pruned: prot._model = self to_add = [] for prot in pruned: if prot.id not in self.constraints: constraint = self.problem.Constraint(Zero, name=prot.id, lb=0, ub=0) to_add += [constraint] self.add_cons_vars(to_add) context = get_context(self) if context: context(partial(self.proteins.__isub__, pruned)) for x in pruned: context(partial(setattr, x, "_model", None)) self.proteins += pruned self._populate_solver([], None, pruned)
def __imul__(self, coefficient): """Scale coefficients in a reaction by a given value E.g. A -> B becomes 2A -> 2B. If coefficient is less than zero, the reaction is reversed and the bounds are swapped. """ self._metabolites = { met: value * coefficient for met, value in self._metabolites.items() } if coefficient < 0: self.bounds = (-self.upper_bound, -self.lower_bound) if self._model: self._model._populate_solver([self]) context = get_context(self) if context: context(partial(self._model._populate_solver, [self])) context(partial(self.__imul__, 1.0 / coefficient)) return self
def remove_reactions(self, reactions, remove_orphans=False): """Remove reactions from the model. The change is reverted upon exit when using the model as a context. Parameters ---------- reactions : list A list with reactions (`cobra.Reaction`), or their id's, to remove remove_orphans : bool Remove orphaned genes and metabolites from the model as well """ if isinstance(reactions, string_types) or hasattr(reactions, "id"): warn("need to pass in a list") reactions = [reactions] context = get_context(self) for reaction in reactions: # Make sure the reaction is in the model try: reaction = self.reactions[self.reactions.index(reaction)] except ValueError: warn('%s not in %s' % (reaction, self)) else: forward = reaction.forward_variable reverse = reaction.reverse_variable if context: context(partial(self._populate_solver, [reaction])) context(partial(setattr, reaction, '_model', self)) context(partial(self.reactions.add, reaction)) self.remove_cons_vars([forward, reverse]) self.reactions.remove(reaction) reaction._model = None for met in reaction._metabolites: if reaction in met._reaction: met._reaction.remove(reaction) if context: context(partial(met._reaction.add, reaction)) if remove_orphans and len(met._reaction) == 0: self.remove_metabolites(met) for gene in reaction._genes: if reaction in gene._reaction: gene._reaction.remove(reaction) if context: context(partial(gene._reaction.add, reaction)) if remove_orphans and len(gene._reaction) == 0: self.genes.remove(gene) if context: context(partial(self.genes.add, gene))
def remove_reactions(self, reactions, remove_orphans=False): """Remove reactions from the model. The change is reverted upon exit when using the model as a context. Parameters ---------- reactions : list A list with reactions (`cobra.Reaction`), or their id's, to remove remove_orphans : bool Remove orphaned genes and metabolites from the model as well """ if isinstance(reactions, string_types) or hasattr(reactions, "id"): warn("need to pass in a list") reactions = [reactions] context = get_context(self) for reaction in reactions: # Make sure the reaction is in the model try: reaction = self.reactions[self.reactions.index(reaction)] except ValueError: warn('%s not in %s' % (reaction, self)) else: forward = reaction.forward_variable reverse = reaction.reverse_variable if context: context(partial(self._populate_solver, [reaction])) context(partial(setattr, reaction, '_model', self)) context(partial(self.reactions.add, reaction)) self.remove_cons_vars([forward, reverse]) self.reactions.remove(reaction) reaction._model = None for met in reaction._metabolites: if reaction in met._reaction: met._reaction.remove(reaction) if context: context(partial(met._reaction.add, reaction)) if remove_orphans and len(met._reaction) == 0: self.remove_metabolites(met) for gene in reaction._genes: if reaction in gene._reaction: gene._reaction.remove(reaction) if context: context(partial(gene._reaction.add, reaction)) if remove_orphans and len(gene._reaction) == 0: self.genes.remove(gene) if context: context(partial(self.genes.add, gene))
def gene_reaction_rule(self, new_rule): # TODO: Do this :) if get_context(self): warn("Context management not implemented for " "gene reaction rules") self._gene_reaction_rule = new_rule.strip() try: _, gene_names = parse_gpr(self._gene_reaction_rule) except (SyntaxError, TypeError) as e: if "AND" in new_rule or "OR" in new_rule: warn("uppercase AND/OR found in rule '%s' for '%s'" % (new_rule, repr(self))) new_rule = uppercase_AND.sub("and", new_rule) new_rule = uppercase_OR.sub("or", new_rule) self.gene_reaction_rule = new_rule return warn("malformed gene_reaction_rule '%s' for %s" % (new_rule, repr(self))) tmp_str = and_or_search.sub("", self._gene_reaction_rule) gene_names = set((gpr_clean.sub(" ", tmp_str).split(" "))) if "" in gene_names: gene_names.remove("") old_genes = self._genes if self._model is None: self._genes = {Gene(i) for i in gene_names} else: model_genes = self._model.genes self._genes = set() for id in gene_names: if model_genes.has_id(id): self._genes.add(model_genes.get_by_id(id)) else: new_gene = Gene(id) new_gene._model = self._model self._genes.add(new_gene) model_genes.append(new_gene) # Make the genes aware that it is involved in this reaction for g in self._genes: g._reaction.add(self) # make the old genes aware they are no longer involved in this reaction for g in old_genes: if g not in self._genes: # if an old gene is not a new gene try: g._reaction.remove(self) except KeyError: warn("could not remove old gene %s from reaction %s" % (g.id, self.id))
def gene_reaction_rule(self, new_rule): # TODO: Do this :) if get_context(self): warn("Context management not implemented for " "gene reaction rules") self._gene_reaction_rule = new_rule.strip() try: _, gene_names = parse_gpr(self._gene_reaction_rule) except (SyntaxError, TypeError) as e: if "AND" in new_rule or "OR" in new_rule: warn("uppercase AND/OR found in rule '%s' for '%s'" % (new_rule, repr(self))) new_rule = uppercase_AND.sub("and", new_rule) new_rule = uppercase_OR.sub("or", new_rule) self.gene_reaction_rule = new_rule return warn("malformed gene_reaction_rule '%s' for %s" % (new_rule, repr(self))) tmp_str = and_or_search.sub('', self._gene_reaction_rule) gene_names = set((gpr_clean.sub(' ', tmp_str).split(' '))) if '' in gene_names: gene_names.remove('') old_genes = self._genes if self._model is None: self._genes = {Gene(i) for i in gene_names} else: model_genes = self._model.genes self._genes = set() for id in gene_names: if model_genes.has_id(id): self._genes.add(model_genes.get_by_id(id)) else: new_gene = Gene(id) new_gene._model = self._model self._genes.add(new_gene) model_genes.append(new_gene) # Make the genes aware that it is involved in this reaction for g in self._genes: g._reaction.add(self) # make the old genes aware they are no longer involved in this reaction for g in old_genes: if g not in self._genes: # if an old gene is not a new gene try: g._reaction.remove(self) except: warn("could not remove old gene %s from reaction %s" % (g.id, self.id))
def add_metabolites(self, metabolite_list): """Will add a list of metabolites to the model object and add new constraints accordingly. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolite_list : A list of `cobra.core.Metabolite` objects """ if not hasattr(metabolite_list, "__iter__"): metabolite_list = [metabolite_list] if len(metabolite_list) == 0: return None # First check whether the metabolites exist in the model metabolite_list = [ x for x in metabolite_list if x.id not in self.metabolites ] bad_ids = [ m for m in metabolite_list if not isinstance(m.id, string_types) or len(m.id) < 1 ] if len(bad_ids) != 0: raise ValueError("invalid identifiers in {}".format(repr(bad_ids))) for x in metabolite_list: x._model = self self.metabolites += metabolite_list # from cameo ... to_add = [] for met in metabolite_list: if met.id not in self.constraints: constraint = self.problem.Constraint(Zero, name=met.id, lb=0, ub=0) to_add += [constraint] self.add_cons_vars(to_add) context = get_context(self) if context: context(partial(self.metabolites.__isub__, metabolite_list)) for x in metabolite_list: # Do we care? context(partial(setattr, x, "_model", None))
def remove_metabolites(self, metabolite_list, destructive=False): """Remove a list of metabolites from the the object. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolite_list : list A list with `cobra.Metabolite` objects as elements. destructive : bool If False then the metabolite is removed from all associated reactions. If True then all associated reactions are removed from the Model. """ if not hasattr(metabolite_list, "__iter__"): metabolite_list = [metabolite_list] # Make sure metabolites exist in model metabolite_list = [ x for x in metabolite_list if x.id in self.metabolites ] for x in metabolite_list: x._model = None # remove reference to the metabolite in all groups associated_groups = self.get_associated_groups(x) for group in associated_groups: group.remove_members(x) if not destructive: for the_reaction in list(x._reaction): the_coefficient = the_reaction._metabolites[x] the_reaction.subtract_metabolites({x: the_coefficient}) else: for x in list(x._reaction): x.remove_from_model() self.metabolites -= metabolite_list to_remove = [self.solver.constraints[m.id] for m in metabolite_list] self.remove_cons_vars(to_remove) context = get_context(self) if context: context(partial(self.metabolites.__iadd__, metabolite_list)) for x in metabolite_list: context(partial(setattr, x, "_model", self))
def add_metabolites(self, metabolite_list): """Will add a list of metabolites to the model object and add new constraints accordingly. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolite_list : A list of `cobra.core.Metabolite` objects """ if not hasattr(metabolite_list, '__iter__'): metabolite_list = [metabolite_list] if len(metabolite_list) == 0: return None # First check whether the metabolites exist in the model metabolite_list = [x for x in metabolite_list if x.id not in self.metabolites] bad_ids = [m for m in metabolite_list if not isinstance(m.id, string_types) or len(m.id) < 1] if len(bad_ids) != 0: raise ValueError('invalid identifiers in {}'.format(repr(bad_ids))) for x in metabolite_list: x._model = self self.metabolites += metabolite_list # from cameo ... to_add = [] for met in metabolite_list: if met.id not in self.constraints: constraint = self.problem.Constraint( Zero, name=met.id, lb=0, ub=0) to_add += [constraint] self.add_cons_vars(to_add) context = get_context(self) if context: context(partial(self.metabolites.__isub__, metabolite_list)) for x in metabolite_list: # Do we care? context(partial(setattr, x, '_model', None))
def remove_metabolites(self, metabolite_list, destructive=False): """Remove a list of metabolites from the the object. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolite_list : list A list with `cobra.Metabolite` objects as elements. destructive : bool If False then the metabolite is removed from all associated reactions. If True then all associated reactions are removed from the Model. """ if not hasattr(metabolite_list, '__iter__'): metabolite_list = [metabolite_list] # Make sure metabolites exist in model metabolite_list = [x for x in metabolite_list if x.id in self.metabolites] for x in metabolite_list: x._model = None if not destructive: for the_reaction in list(x._reaction): the_coefficient = the_reaction._metabolites[x] the_reaction.subtract_metabolites({x: the_coefficient}) else: for x in list(x._reaction): x.remove_from_model() self.metabolites -= metabolite_list to_remove = [self.solver.constraints[m.id] for m in metabolite_list] self.remove_cons_vars(to_remove) context = get_context(self) if context: context(partial(self.metabolites.__iadd__, metabolite_list)) for x in metabolite_list: context(partial(setattr, x, '_model', self))
def add_metabolites(self, metabolite_list): """Will add a list of metabolites to the model object and add new constraints accordingly. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolite_list : A list of `cobra.core.Metabolite` objects """ if not hasattr(metabolite_list, '__iter__'): metabolite_list = [metabolite_list] if len(metabolite_list) == 0: return None # First check whether the metabolites exist in the model metabolite_list = [ x for x in metabolite_list if x.id not in self.metabolites ] for x in metabolite_list: x._model = self self.metabolites += metabolite_list # from cameo ... to_add = [] for met in metabolite_list: if met.id not in self.constraints: constraint = self.problem.Constraint(S.Zero, name=met.id, lb=0, ub=0) to_add += [constraint] self.add_cons_vars(to_add) context = get_context(self) if context: context(partial(self.metabolites.__isub__, metabolite_list)) for x in metabolite_list: # Do we care? context(partial(setattr, x, '_model', None))
def remove_cons_vars_from_problem(model, what): """Remove variables and constraints from a Model's solver object. Useful to temporarily remove variables and constraints from a Models's solver object. Parameters ---------- model : a cobra model The model from which to remove the variables and constraints. what : list or tuple of optlang variables or constraints. The variables or constraints to remove from the model. Must be of class `model.problem.Variable` or `model.problem.Constraint`. """ context = get_context(model) model.solver.remove(what) if context: context(partial(model.solver.add, what))
def remove_cons_vars_from_problem(model, what): """Remove variables and constraints from a Model's solver object. Useful to temporarily remove variables and constraints from a Models's solver object. Parameters ---------- model : a cobra model The model from which to remove the variables and constraints. what : list or tuple of optlang variables or constraints. The variables or constraints to remove from the model. Must be of class `model.problem.Variable` or `model.problem.Constraint`. """ context = get_context(model) model.solver.remove(what) if context: context(partial(model.solver.add, what))
def _apply_min_growth(community, min_growth): """Set minimum growth constraints on a model. Will integrate with the context. """ context = get_context(community) def reset(species, lb): logger.info("resetting growth rate constraint for %s" % species) community.constraints["objective_" + species].ub = None community.constraints["objective_" + species].lb = lb for sp in community.species: logger.info("setting growth rate constraint for %s" % sp) obj = community.constraints["objective_" + sp] if context: context(partial(reset, sp, obj.lb)) if min_growth[sp] > 1e-6: obj.lb = min_growth[sp] else: logger.info("minimal growth rate smaller than tolerance," " setting to zero.") obj.lb = 0
def remove_cons_vars_from_problem( model: "Model", what: Union[List[CONS_VARS], Tuple[CONS_VARS], Components], ) -> None: """Remove variables and constraints from a model's solver object. Useful to temporarily remove variables and constraints from a model's solver object. Parameters ---------- model : cobra.Model The model from which to remove the variables and constraints. what : list or tuple of optlang.interface.Variable or optlang.interface.Constraint The variables and constraints to remove from the model. """ model.solver.remove(what) context = get_context(model) if context: context(partial(model.solver.add, what))
def add_cons_vars_to_problem(model, what, **kwargs): """Add variables and constraints to a Model's solver object. Useful for variables and constraints that can not be expressed with reactions and lower/upper bounds. Will integrate with the Model's context manager in order to revert changes upon leaving the context. Parameters ---------- model : a cobra model The model to which to add the variables and constraints. what : list or tuple of optlang variables or constraints. The variables or constraints to add to the model. Must be of class `model.problem.Variable` or `model.problem.Constraint`. **kwargs : keyword arguments passed to solver.add() """ context = get_context(model) model.solver.add(what, **kwargs) if context: context(partial(model.solver.remove, what))
def add_cons_vars_to_problem(model, what, **kwargs): """Add variables and constraints to a Model's solver object. Useful for variables and constraints that can not be expressed with reactions and lower/upper bounds. Will integrate with the Model's context manager in order to revert changes upon leaving the context. Parameters ---------- model : a cobra model The model to which to add the variables and constraints. what : list or tuple of optlang variables or constraints. The variables or constraints to add to the model. Must be of class `model.problem.Variable` or `model.problem.Constraint`. **kwargs : keyword arguments passed to solver.add() """ context = get_context(model) model.solver.add(what, **kwargs) if context: context(partial(model.solver.remove, what))
def __imul__(self, coefficient): """Scale coefficients in a reaction by a given value E.g. A -> B becomes 2A -> 2B. If coefficient is less than zero, the reaction is reversed and the bounds are swapped. """ self._metabolites = { met: value * coefficient for met, value in iteritems(self._metabolites)} if coefficient < 0: self.bounds = (-self.upper_bound, -self.lower_bound) if self._model: self._model._populate_solver([self]) context = get_context(self) if context: context(partial(self._model._populate_solver, [self])) context(partial(self.__imul__, 1./coefficient)) return self
def add_reactions(self, reaction_list): """Add reactions to the model. Reactions with identifiers identical to a reaction already in the model are ignored. The change is reverted upon exit when using the model as a context. Parameters ---------- reaction_list : list A list of `cobra.Reaction` objects """ def existing_filter(rxn): if rxn.id in self.reactions: LOGGER.warning( "Ignoring reaction '%s' since it already exists.", rxn.id) return False return True # First check whether the reactions exist in the model. pruned = DictList(filter(existing_filter, reaction_list)) context = get_context(self) # Add reactions. Also take care of genes and metabolites in the loop. for reaction in pruned: reaction._model = self # Build a `list()` because the dict will be modified in the loop. for metabolite in list(reaction.metabolites): # TODO: Should we add a copy of the metabolite instead? if metabolite not in self.metabolites: self.add_metabolites(metabolite) # A copy of the metabolite exists in the model, the reaction # needs to point to the metabolite in the model. else: # FIXME: Modifying 'private' attributes is horrible. stoichiometry = reaction._metabolites.pop(metabolite) model_metabolite = self.metabolites.get_by_id( metabolite.id) reaction._metabolites[model_metabolite] = stoichiometry model_metabolite._reaction.add(reaction) if context: context(partial( model_metabolite._reaction.remove, reaction)) for gene in list(reaction._genes): # If the gene is not in the model, add it if not self.genes.has_id(gene.id): self.genes += [gene] gene._model = self if context: # Remove the gene later context(partial(self.genes.__isub__, [gene])) context(partial(setattr, gene, '_model', None)) # Otherwise, make the gene point to the one in the model else: model_gene = self.genes.get_by_id(gene.id) if model_gene is not gene: reaction._dissociate_gene(gene) reaction._associate_gene(model_gene) self.reactions += pruned if context: context(partial(self.reactions.__isub__, pruned)) # from cameo ... self._populate_solver(pruned)
def add_reactions(self, reaction_list: Iterator[Reaction]): """Add reactions to the model. Reactions with identifiers identical to a reaction already in the model are ignored. The change is reverted upon exit when using the model as a context. Enzyme Constrained changes: avoid adding proteins as metabolites. Parameters ---------- reaction_list : list A list of `cobra.Reaction` objects """ def existing_filter(rxn): if rxn.id in self.reactions: LOGGER.warning( f"Ignoring reaction '{rxn.id}' since it already exists.") return False return True # First check whether the reactions exist in the model. pruned = DictList(filter(existing_filter, reaction_list)) context = get_context(self) # Add reactions. Also take care of genes and metabolites in the loop. for reaction in pruned: reaction._model = self # Build a `list()` because the dict will be modified in the loop. for metabolite in list(reaction.metabolites): is_prot = isinstance(metabolite, Protein) target = self.proteins if is_prot else self.metabolites if metabolite not in target: if is_prot: self.add_proteins([metabolite]) else: self.add_metabolites(metabolite) # A copy of the metabolite exists in the model, the reaction # needs to point to the metabolite in the model. else: stoichiometry = reaction._metabolites.pop(metabolite) model_metabolite = target.get_by_id(metabolite.id) reaction._metabolites[model_metabolite] = stoichiometry model_metabolite._reaction.add(reaction) if context: context( partial(model_metabolite._reaction.remove, reaction)) for gene in list(reaction._genes): # If the gene is not in the model, add it if not self.genes.has_id(gene.id): self.genes += [gene] gene._model = self if context: # Remove the gene later context(partial(self.genes.__isub__, [gene])) context(partial(setattr, gene, "_model", None)) # Otherwise, make the gene point to the one in the model else: model_gene = self.genes.get_by_id(gene.id) if model_gene is not gene: reaction._dissociate_gene(gene) reaction._associate_gene(model_gene) self.reactions += pruned if context: context(partial(self.reactions.__isub__, pruned)) # from cameo ... self._populate_solver(pruned)
def set_objective(model, value, additive=False): """Set the model objective. Parameters ---------- model : cobra model The model to set the objective for value : model.problem.Objective, e.g. optlang.glpk_interface.Objective, sympy.Basic or dict If the model objective is linear, the value can be a new Objective object or a dictionary with linear coefficients where each key is a reaction and the element the new coefficient (float). If the objective is not linear and `additive` is true, only values of class Objective. additive : boolmodel.reactions.Biomass_Ecoli_core.bounds = (0.1, 0.1) If true, add the terms to the current objective, otherwise start with an empty objective. """ interface = model.problem reverse_value = model.solver.objective.expression reverse_value = interface.Objective( reverse_value, direction=model.solver.objective.direction, sloppy=True) if isinstance(value, dict): if not model.objective.is_Linear: raise ValueError('can only update non-linear objectives ' 'additively using object of class ' 'model.problem.Objective, not %s' % type(value)) if not additive: model.solver.objective = interface.Objective( Zero, direction=model.solver.objective.direction) for reaction, coef in value.items(): model.solver.objective.set_linear_coefficients( {reaction.forward_variable: coef, reaction.reverse_variable: -coef}) elif isinstance(value, (Basic, optlang.interface.Objective)): if isinstance(value, Basic): value = interface.Objective( value, direction=model.solver.objective.direction, sloppy=False) # Check whether expression only uses variables from current model # clone the objective if not, faster than cloning without checking if not _valid_atoms(model, value.expression): value = interface.Objective.clone(value, model=model.solver) if not additive: model.solver.objective = value else: model.solver.objective += value.expression else: raise TypeError( '%r is not a valid objective for %r.' % (value, model.solver)) context = get_context(model) if context: def reset(): model.solver.objective = reverse_value model.solver.objective.direction = reverse_value.direction context(reset)
def remove_reactions(self, reactions, delete=True, remove_orphans=False): """Remove reactions from the model. The change is reverted upon exit when using the model as a context. Parameters ---------- reactions : list A list with reactions (`cobra.Reaction`), or their id's, to remove delete : bool Whether or not the reactions should be deleted after removal. If the reactions are not deleted, those objects will be recreated with new metabolite and gene objects. remove_orphans : bool Remove orphaned genes and metabolites from the model as well """ if isinstance(reactions, string_types) or hasattr(reactions, "id"): warn("need to pass in a list") reactions = [reactions] context = get_context(self) for reaction in reactions: try: reaction = self.reactions[self.reactions.index(reaction)] except ValueError: warn('%s not in %s' % (reaction, self)) else: forward = reaction.forward_variable reverse = reaction.reverse_variable self.remove_cons_vars([forward, reverse]) self.reactions.remove(reaction) reaction._model = None if context: context(partial(setattr, reaction, '_model', self)) context(partial(self.reactions.add, reaction)) for x in reaction._metabolites: if reaction in x._reaction: x._reaction.remove(reaction) if context: context(partial(x._reaction.add, reaction)) if remove_orphans and len(x._reaction) == 0: self.remove_metabolites(x) for x in reaction._genes: if reaction in x._reaction: x._reaction.remove(reaction) if context: context(partial(x._reaction.add, reaction)) if remove_orphans and len(x._reaction) == 0: self.genes.remove(x) if context: context(partial(self.genes.add, x)) reaction._metabolites = {} reaction._genes = set()
def add_reactions(self, reaction_list): """Will add a cobra.Reaction object to the model, if reaction.id is not in self.reactions. The change is reverted upon exit when using the model as a context. Parameters ---------- reaction_list : list A list of `cobra.Reaction` objects """ try: reaction_list = DictList(reaction_list) except TypeError: reaction_list = DictList([reaction_list]) # Only add the reaction if one with the same ID is not already # present in the model. reactions_in_model = [ i.id for i in reaction_list if i.id in self.reactions ] if len(reactions_in_model) > 0: raise Exception("Reactions already in the model: " + ", ".join(reactions_in_model)) context = get_context(self) # Add reactions. Also take care of genes and metabolites in the loop for reaction in reaction_list: reaction._reset_var_cache() reaction._model = self # the reaction now points to the model # keys() is necessary because the dict will be modified during # the loop for metabolite in list(reaction._metabolites.keys()): # if the metabolite is not in the model, add it # should we be adding a copy instead. if metabolite not in self.metabolites: self.add_metabolites(metabolite) # A copy of the metabolite exists in the model, the reaction # needs to point to the metabolite in the model. else: stoichiometry = reaction._metabolites.pop(metabolite) model_metabolite = self.metabolites.get_by_id( metabolite.id) reaction._metabolites[model_metabolite] = stoichiometry model_metabolite._reaction.add(reaction) if context: context( partial(model_metabolite._reaction.remove, reaction)) for gene in list(reaction._genes): # If the gene is not in the model, add it if not self.genes.has_id(gene.id): self.genes += [gene] gene._model = self if context: # Remove the gene later context(partial(self.genes.__isub__, [gene])) context(partial(setattr, gene, '_model', None)) # Otherwise, make the gene point to the one in the model else: model_gene = self.genes.get_by_id(gene.id) if model_gene is not gene: reaction._dissociate_gene(gene) reaction._associate_gene(model_gene) self.reactions += reaction_list if context: context(partial(self.reactions.__isub__, reaction_list)) # from cameo ... self._populate_solver(reaction_list)
def add_metabolites(self, metabolites_to_add, combine=True, reversibly=True): """Add metabolites and stoichiometric coefficients to the reaction. If the final coefficient for a metabolite is 0 then it is removed from the reaction. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolites_to_add : dict Dictionary with metabolite objects or metabolite identifiers as keys and coefficients as values. combine : bool Describes behavior a metabolite already exists in the reaction. True causes the coefficients to be added. False causes the coefficient to be replaced. reversibly : bool Whether to add the change to the context to make the change reversibly or not (primarily intended for internal use). """ old_coefficients = self.metabolites new_metabolites = [] _id_to_metabolites = dict([(x.id, x) for x in self._metabolites]) for metabolite, coefficient in iteritems(metabolites_to_add): met_id = str(metabolite) # If a metabolite already exists in the reaction then # just add them. if met_id in _id_to_metabolites: reaction_metabolite = _id_to_metabolites[met_id] if combine: self._metabolites[reaction_metabolite] += coefficient else: self._metabolites[reaction_metabolite] = coefficient else: # If the reaction is in a model, ensure we aren't using # a duplicate metabolite. if self._model: try: metabolite = \ self._model.metabolites.get_by_id(met_id) except KeyError as e: if isinstance(metabolite, Metabolite): new_metabolites.append(metabolite) else: # do we want to handle creation here? raise e elif isinstance(metabolite, string_types): # if we want to handle creation, this should be changed raise ValueError( "reaction '%s' does not belong to a model" % self.id) self._metabolites[metabolite] = coefficient # make the metabolite aware that it is involved in this # reaction metabolite._reaction.add(self) for metabolite, the_coefficient in list(self._metabolites.items()): if the_coefficient == 0: # make the metabolite aware that it no longer participates # in this reaction metabolite._reaction.remove(self) self._metabolites.pop(metabolite) # from cameo ... model = self.model if model is not None: model.add_metabolites(new_metabolites) for metabolite, coefficient in metabolites_to_add.items(): if isinstance(metabolite, str): # support metabolites added as strings. metabolite = model.metabolites.get_by_id(metabolite) if combine: try: old_coefficient = old_coefficients[metabolite] except KeyError: pass else: coefficient = coefficient + old_coefficient model.constraints[metabolite.id].set_linear_coefficients({ self.forward_variable: coefficient, self.reverse_variable: -coefficient }) context = get_context(self) if context and reversibly: # Just subtract the metabolites that were added context( partial(self.subtract_metabolites, metabolites_to_add, combine=True, reversibly=False))
def add_reactions(self, reaction_list): """Add reactions to the model. Reactions with identifiers identical to a reaction already in the model are ignored. The change is reverted upon exit when using the model as a context. Parameters ---------- reaction_list : list A list of `cobra.Reaction` objects """ try: reaction_list = DictList(reaction_list) except TypeError: reaction_list = DictList([reaction_list]) # First check whether the metabolites exist in the model existing = [rxn for rxn in reaction_list if rxn.id in self.reactions] for rxn in existing: LOGGER.info('skip adding reaction %s as already existing', rxn.id) reaction_list = [ rxn for rxn in reaction_list if rxn.id not in existing ] context = get_context(self) # Add reactions. Also take care of genes and metabolites in the loop for reaction in reaction_list: reaction._reset_var_cache() reaction._model = self # the reaction now points to the model # keys() is necessary because the dict will be modified during # the loop for metabolite in list(reaction._metabolites.keys()): # if the metabolite is not in the model, add it # should we be adding a copy instead. if metabolite not in self.metabolites: self.add_metabolites(metabolite) # A copy of the metabolite exists in the model, the reaction # needs to point to the metabolite in the model. else: stoichiometry = reaction._metabolites.pop(metabolite) model_metabolite = self.metabolites.get_by_id( metabolite.id) reaction._metabolites[model_metabolite] = stoichiometry model_metabolite._reaction.add(reaction) if context: context( partial(model_metabolite._reaction.remove, reaction)) for gene in list(reaction._genes): # If the gene is not in the model, add it if not self.genes.has_id(gene.id): self.genes += [gene] gene._model = self if context: # Remove the gene later context(partial(self.genes.__isub__, [gene])) context(partial(setattr, gene, '_model', None)) # Otherwise, make the gene point to the one in the model else: model_gene = self.genes.get_by_id(gene.id) if model_gene is not gene: reaction._dissociate_gene(gene) reaction._associate_gene(model_gene) self.reactions += reaction_list if context: context(partial(self.reactions.__isub__, reaction_list)) # from cameo ... self._populate_solver(reaction_list)
def set_objective(model, value, additive=False): """Set the model objective. Parameters ---------- model : cobra model The model to set the objective for value : model.problem.Objective, e.g. optlang.glpk_interface.Objective, sympy.Basic or dict If the model objective is linear, the value can be a new Objective object or a dictionary with linear coefficients where each key is a reaction and the element the new coefficient (float). If the objective is not linear and `additive` is true, only values of class Objective. additive : boolmodel.reactions.Biomass_Ecoli_core.bounds = (0.1, 0.1) If true, add the terms to the current objective, otherwise start with an empty objective. """ interface = model.problem reverse_value = model.solver.objective.expression reverse_value = interface.Objective( reverse_value, direction=model.solver.objective.direction, sloppy=True) if isinstance(value, dict): if not model.objective.is_Linear: raise ValueError('can only update non-linear objectives ' 'additively using object of class ' 'model.problem.Objective, not %s' % type(value)) if not additive: model.solver.objective = interface.Objective( Zero, direction=model.solver.objective.direction) for reaction, coef in value.items(): model.solver.objective.set_linear_coefficients( {reaction.forward_variable: coef, reaction.reverse_variable: -coef}) elif isinstance(value, (Basic, optlang.interface.Objective)): if isinstance(value, Basic): value = interface.Objective( value, direction=model.solver.objective.direction, sloppy=False) # Check whether expression only uses variables from current model # clone the objective if not, faster than cloning without checking if not _valid_atoms(model, value.expression): value = interface.Objective.clone(value, model=model.solver) if not additive: model.solver.objective = value else: model.solver.objective += value.expression else: raise TypeError( '%r is not a valid objective for %r.' % (value, model.solver)) context = get_context(model) if context: def reset(): model.solver.objective = reverse_value model.solver.objective.direction = reverse_value.direction context(reset)
def set_objective( model: "Model", value: Union[optlang.interface.Objective, optlang.symbolics.Basic, Dict["Reaction", float], ], additive: bool = False, ) -> None: """Set the model objective. Parameters ---------- model : cobra.Model The model to set the objective for. value : optlang.interface.Objective, optlang.symbolics.Basic, dict If the model objective is linear, then the value can be a new optlang.interface.Objective or a dictionary with linear coefficients where each key is a reaction and the corresponding value is the new coefficient (float). If the objective is non-linear and `additive` is True, then only values of class optlang.interface.Objective, are accepted. additive : bool If True, add the terms to the current objective, otherwise start with an empty objective. Raises ------ ValueError If model objective is non-linear and the `value` is a dict. TypeError If the type of `value` is not one of the accepted ones. """ interface = model.problem reverse_value = model.solver.objective.expression reverse_value = interface.Objective( reverse_value, direction=model.solver.objective.direction, sloppy=True) if isinstance(value, dict): if not model.objective.is_Linear: raise ValueError( "You can only update non-linear objectives additively using object of " f"class optlang.interface.Objective, not of {type(value)}") if not additive: model.solver.objective = interface.Objective( Zero, direction=model.solver.objective.direction) for reaction, coef in value.items(): model.solver.objective.set_linear_coefficients({ reaction.forward_variable: coef, reaction.reverse_variable: -coef }) elif isinstance(value, (Basic, optlang.interface.Objective)): if isinstance(value, Basic): value = interface.Objective( value, direction=model.solver.objective.direction, sloppy=False) # Check whether expression only uses variables from current model; # clone the objective if not, faster than cloning without checking if not _valid_atoms(model, value.expression): value = interface.Objective.clone(value, model=model.solver) if not additive: model.solver.objective = value else: model.solver.objective += value.expression else: raise TypeError( f"{value} is not a valid objective for {model.solver}.") context = get_context(model) if context: def reset(): model.solver.objective = reverse_value model.solver.objective.direction = reverse_value.direction context(reset)
def remove_reactions(self, reactions, remove_orphans=False): """Remove reactions from the model. The change is reverted upon exit when using the model as a context. Parameters ---------- reactions : list A list with reactions (`cobra.Reaction`), or their id's, to remove remove_orphans : bool Remove orphaned genes and metabolites from the model as well """ if isinstance(reactions, string_types) or hasattr(reactions, "id"): warn("need to pass in a list") reactions = [reactions] context = get_context(self) for reaction in reactions: # Make sure the reaction is in the model try: reaction = self.reactions[self.reactions.index(reaction)] except ValueError: warn("%s not in %s" % (reaction, self)) else: forward = reaction.forward_variable reverse = reaction.reverse_variable if context: obj_coef = reaction.objective_coefficient if obj_coef != 0: context( partial( self.solver.objective.set_linear_coefficients, { forward: obj_coef, reverse: -obj_coef }, )) context(partial(self._populate_solver, [reaction])) context(partial(setattr, reaction, "_model", self)) context(partial(self.reactions.add, reaction)) self.remove_cons_vars([forward, reverse]) self.reactions.remove(reaction) reaction._model = None for met in reaction._metabolites: if reaction in met._reaction: met._reaction.remove(reaction) if context: context(partial(met._reaction.add, reaction)) if remove_orphans and len(met._reaction) == 0: self.remove_metabolites(met) for gene in reaction._genes: if reaction in gene._reaction: gene._reaction.remove(reaction) if context: context(partial(gene._reaction.add, reaction)) if remove_orphans and len(gene._reaction) == 0: self.genes.remove(gene) if context: context(partial(self.genes.add, gene)) # remove reference to the reaction in all groups associated_groups = self.get_associated_groups(reaction) for group in associated_groups: group.remove_members(reaction)
def add_reactions(self, reaction_list): """Add reactions to the model. Reactions with identifiers identical to a reaction already in the model are ignored. The change is reverted upon exit when using the model as a context. Parameters ---------- reaction_list : list A list of `cobra.Reaction` objects """ def existing_filter(rxn): if rxn.id in self.reactions: logger.warning( "Ignoring reaction '%s' since it already exists.", rxn.id) return False return True # First check whether the reactions exist in the model. pruned = DictList(filter(existing_filter, reaction_list)) context = get_context(self) # Add reactions. Also take care of genes and metabolites in the loop. for reaction in pruned: reaction._model = self # Build a `list()` because the dict will be modified in the loop. for metabolite in list(reaction.metabolites): # TODO: Should we add a copy of the metabolite instead? if metabolite not in self.metabolites: self.add_metabolites(metabolite) # A copy of the metabolite exists in the model, the reaction # needs to point to the metabolite in the model. else: # FIXME: Modifying 'private' attributes is horrible. stoichiometry = reaction._metabolites.pop(metabolite) model_metabolite = self.metabolites.get_by_id( metabolite.id) reaction._metabolites[model_metabolite] = stoichiometry model_metabolite._reaction.add(reaction) if context: context( partial(model_metabolite._reaction.remove, reaction)) for gene in list(reaction._genes): # If the gene is not in the model, add it if not self.genes.has_id(gene.id): self.genes += [gene] gene._model = self if context: # Remove the gene later context(partial(self.genes.__isub__, [gene])) context(partial(setattr, gene, "_model", None)) # Otherwise, make the gene point to the one in the model else: model_gene = self.genes.get_by_id(gene.id) if model_gene is not gene: reaction._dissociate_gene(gene) reaction._associate_gene(model_gene) self.reactions += pruned if context: context(partial(self.reactions.__isub__, pruned))
def add_metabolites(self, metabolites_to_add, combine=True, reversibly=True): """Add metabolites and stoichiometric coefficients to the reaction. If the final coefficient for a metabolite is 0 then it is removed from the reaction. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolites_to_add : dict Dictionary with metabolite objects or metabolite identifiers as keys and coefficients as values. If keys are strings (name of a metabolite) the reaction must already be part of a model and a metabolite with the given name must exist in the model. combine : bool Describes behavior a metabolite already exists in the reaction. True causes the coefficients to be added. False causes the coefficient to be replaced. reversibly : bool Whether to add the change to the context to make the change reversibly or not (primarily intended for internal use). """ old_coefficients = self.metabolites new_metabolites = [] _id_to_metabolites = dict([(x.id, x) for x in self._metabolites]) for metabolite, coefficient in metabolites_to_add.items(): # Make sure metabolites being added belong to the same model, or # else copy them. if isinstance(metabolite, Metabolite): if (metabolite.model is not None) and (metabolite.model is not self._model): metabolite = metabolite.copy() met_id = str(metabolite) # If a metabolite already exists in the reaction then # just add them. if met_id in _id_to_metabolites: reaction_metabolite = _id_to_metabolites[met_id] if combine: self._metabolites[reaction_metabolite] += coefficient else: self._metabolites[reaction_metabolite] = coefficient else: # If the reaction is in a model, ensure we aren't using # a duplicate metabolite. if self._model: try: metabolite = self._model.metabolites.get_by_id(met_id) except KeyError as e: if isinstance(metabolite, Metabolite): new_metabolites.append(metabolite) else: # do we want to handle creation here? raise e elif isinstance(metabolite, str): # if we want to handle creation, this should be changed raise ValueError("Reaction '%s' does not belong to a " "model. Either add the reaction to a " "model or use Metabolite objects instead " "of strings as keys." % self.id) self._metabolites[metabolite] = coefficient # make the metabolite aware that it is involved in this # reaction metabolite._reaction.add(self) # from cameo ... model = self.model if model is not None: model.add_metabolites(new_metabolites) for metabolite, coefficient in self._metabolites.items(): model.constraints[metabolite.id].set_linear_coefficients({ self.forward_variable: coefficient, self.reverse_variable: -coefficient, }) for metabolite, the_coefficient in list(self._metabolites.items()): if the_coefficient == 0: # make the metabolite aware that it no longer participates # in this reaction metabolite._reaction.remove(self) self._metabolites.pop(metabolite) context = get_context(self) if context and reversibly: if combine: # Just subtract the metabolites that were added context( partial( self.subtract_metabolites, metabolites_to_add, combine=True, reversibly=False, )) else: # Reset them with add_metabolites mets_to_reset = { key: old_coefficients[model.metabolites.get_by_any(key)[0]] for key in metabolites_to_add.keys() } context( partial( self.add_metabolites, mets_to_reset, combine=False, reversibly=False, ))
def add_metabolites(self, metabolites_to_add, combine=True, reversibly=True): """Add metabolites and stoichiometric coefficients to the reaction. If the final coefficient for a metabolite is 0 then it is removed from the reaction. The change is reverted upon exit when using the model as a context. Parameters ---------- metabolites_to_add : dict Dictionary with metabolite objects or metabolite identifiers as keys and coefficients as values. If keys are strings (name of a metabolite) the reaction must already be part of a model and a metabolite with the given name must exist in the model. combine : bool Describes behavior a metabolite already exists in the reaction. True causes the coefficients to be added. False causes the coefficient to be replaced. reversibly : bool Whether to add the change to the context to make the change reversibly or not (primarily intended for internal use). """ old_coefficients = self.metabolites new_metabolites = [] _id_to_metabolites = dict([(x.id, x) for x in self._metabolites]) for metabolite, coefficient in iteritems(metabolites_to_add): met_id = str(metabolite) # If a metabolite already exists in the reaction then # just add them. if met_id in _id_to_metabolites: reaction_metabolite = _id_to_metabolites[met_id] if combine: self._metabolites[reaction_metabolite] += coefficient else: self._metabolites[reaction_metabolite] = coefficient else: # If the reaction is in a model, ensure we aren't using # a duplicate metabolite. if self._model: try: metabolite = \ self._model.metabolites.get_by_id(met_id) except KeyError as e: if isinstance(metabolite, Metabolite): new_metabolites.append(metabolite) else: # do we want to handle creation here? raise e elif isinstance(metabolite, string_types): # if we want to handle creation, this should be changed raise ValueError("Reaction '%s' does not belong to a " "model. Either add the reaction to a " "model or use Metabolite objects instead " "of strings as keys." % self.id) self._metabolites[metabolite] = coefficient # make the metabolite aware that it is involved in this # reaction metabolite._reaction.add(self) for metabolite, the_coefficient in list(self._metabolites.items()): if the_coefficient == 0: # make the metabolite aware that it no longer participates # in this reaction metabolite._reaction.remove(self) self._metabolites.pop(metabolite) # from cameo ... model = self.model if model is not None: model.add_metabolites(new_metabolites) for metabolite, coefficient in metabolites_to_add.items(): if isinstance(metabolite, str): # support metabolites added as strings. metabolite = model.metabolites.get_by_id(metabolite) if combine: try: old_coefficient = old_coefficients[metabolite] except KeyError: pass else: coefficient = coefficient + old_coefficient model.constraints[ metabolite.id].set_linear_coefficients( {self.forward_variable: coefficient, self.reverse_variable: -coefficient }) context = get_context(self) if context and reversibly: if combine: # Just subtract the metabolites that were added context(partial( self.subtract_metabolites, metabolites_to_add, combine=True, reversibly=False)) else: # Reset them with add_metabolites mets_to_reset = { key: old_coefficients[model.metabolites.get_by_any(key)[0]] for key in iterkeys(metabolites_to_add)} context(partial( self.add_metabolites, mets_to_reset, combine=False, reversibly=False))