Source code for cobra.core.Metabolite

from warnings import warn
import re

from six import iteritems

from .Species import Species

# Numbers are not required because of the |(?=[A-Z])? block. See the
# discussion in https://github.com/opencobra/cobrapy/issues/128 for
# more details.
element_re = re.compile("([A-Z][a-z]?)([0-9.]+[0-9.]?|(?=[A-Z])?)")


[docs]class Metabolite(Species): """Metabolite is a class for holding information regarding a metabolite in a cobra.Reaction object. """ def __init__(self, id=None, formula=None, name="", charge=None, compartment=None): """ id: str formula: str Chemical formula (i.e. H2O) name: str A human readable name. compartment: None or a dictionary indicating the cellular location of the metabolite. Used when in a cobra.Reaction or Model object """ Species.__init__(self, id, name) self.formula = formula # because in a Model a metabolite may participate in multiple Reactions self.compartment = compartment self.charge = charge self._constraint_sense = 'E' self._bound = 0. @property def elements(self): tmp_formula = self.formula if tmp_formula is None: return {} # necessary for some old pickles which use the deprecated # Formula class tmp_formula = str(self.formula) # commonly occuring characters in incorrectly constructed formulas if "*" in tmp_formula: warn("invalid character '*' found in formula '%s'" % self.formula) tmp_formula = tmp_formula.replace("*", "") if "(" in tmp_formula or ")" in tmp_formula: warn("invalid formula (has parenthesis) in '%s'" % self.formula) return None composition = {} parsed = element_re.findall(tmp_formula) for (element, count) in parsed: if count == '': count = 1 else: try: count = float(count) int_count = int(count) if count == int_count: count = int_count else: warn("%s is not an integer (in formula %s)" % (count, self.formula)) except ValueError: warn("failed to parse %s (in formula %s)" % (count, self.formula)) return None if element in composition: composition[element] += count else: composition[element] = count return composition @elements.setter def elements(self, elements_dict): def stringify(element, number): return element if number == 1 else element + str(number) self.formula = ''.join(stringify(e, n) for e, n in sorted(iteritems(elements_dict))) @property def formula_weight(self): """Calculate the formula weight""" try: return sum([count * elements_and_molecular_weights[element] for element, count in self.elements.items()]) except KeyError as e: warn("The element %s does not appear in the peridic table" % e) @property def y(self): """The shadow price for the metabolite in the most recent solution Shadow prices are computed from the dual values of the bounds in the solution. """ try: return self._model.solution.y_dict[self.id] except Exception as e: if self._model is None: raise Exception("not part of a model") if not hasattr(self._model, "solution") or \ self._model.solution is None or \ self._model.solution.status == "NA": raise Exception("model has not been solved") if self._model.solution.status != "optimal": raise Exception("model solution was not optimal") raise e # Not sure what the exact problem was
[docs] def remove_from_model(self, method='subtractive', **kwargs): """Removes the association from self.model method: 'subtractive' or 'destructive'. If 'subtractive' then the metabolite is removed from all associated reactions. If 'destructive' then all associated reactions are removed from the Model. """ # why is model being taken in as a parameter? This plays # back to the question of allowing a Metabolite to be associated # with multiple Models if "model" in kwargs: warn("model argument deprecated") self._model.metabolites.remove(self) self._model = None if method.lower() == 'subtractive': for the_reaction in list(self._reaction): the_coefficient = the_reaction._metabolites[self] the_reaction.subtract_metabolites({self: the_coefficient}) elif method.lower() == 'destructive': for x in self._reaction: x.remove_from_model() else: raise Exception(method + " is not 'subtractive' or 'destructive'")
[docs] def summary(self, **kwargs): """Print a summary of the reactions which produce and consume this metabolite. This method requires the model for which this metabolite is a part to be solved. threshold: float a value below which to ignore reaction fluxes fva: float (0->1), or None Whether or not to include flux variability analysis in the output. If given, fva should be a float between 0 and 1, representing the fraction of the optimum objective to be searched. """ try: from ..flux_analysis.summary import metabolite_summary return metabolite_summary(self, **kwargs) except ImportError: warn('Summary methods require pandas')
elements_and_molecular_weights = { 'H': 1.007940, 'He': 4.002602, 'Li': 6.941000, 'Be': 9.012182, 'B': 10.811000, 'C': 12.010700, 'N': 14.006700, 'O': 15.999400, 'F': 18.998403, 'Ne': 20.179700, 'Na': 22.989770, 'Mg': 24.305000, 'Al': 26.981538, 'Si': 28.085500, 'P': 30.973761, 'S': 32.065000, 'Cl': 35.453000, 'Ar': 39.948000, 'K': 39.098300, 'Ca': 40.078000, 'Sc': 44.955910, 'Ti': 47.867000, 'V': 50.941500, 'Cr': 51.996100, 'Mn': 54.938049, 'Fe': 55.845000, 'Co': 58.933200, 'Ni': 58.693400, 'Cu': 63.546000, 'Zn': 65.409000, 'Ga': 69.723000, 'Ge': 72.640000, 'As': 74.921600, 'Se': 78.960000, 'Br': 79.904000, 'Kr': 83.798000, 'Rb': 85.467800, 'Sr': 87.620000, 'Y': 88.905850, 'Zr': 91.224000, 'Nb': 92.906380, 'Mo': 95.940000, 'Tc': 98.000000, 'Ru': 101.070000, 'Rh': 102.905500, 'Pd': 106.420000, 'Ag': 107.868200, 'Cd': 112.411000, 'In': 114.818000, 'Sn': 118.710000, 'Sb': 121.760000, 'Te': 127.600000, 'I': 126.904470, 'Xe': 131.293000, 'Cs': 132.905450, 'Ba': 137.327000, 'La': 138.905500, 'Ce': 140.116000, 'Pr': 140.907650, 'Nd': 144.240000, 'Pm': 145.000000, 'Sm': 150.360000, 'Eu': 151.964000, 'Gd': 157.250000, 'Tb': 158.925340, 'Dy': 162.500000, 'Ho': 164.930320, 'Er': 167.259000, 'Tm': 168.934210, 'Yb': 173.040000, 'Lu': 174.967000, 'Hf': 178.490000, 'Ta': 180.947900, 'W': 183.840000, 'Re': 186.207000, 'Os': 190.230000, 'Ir': 192.217000, 'Pt': 195.078000, 'Au': 196.966550, 'Hg': 200.590000, 'Tl': 204.383300, 'Pb': 207.200000, 'Bi': 208.980380, 'Po': 209.000000, 'At': 210.000000, 'Rn': 222.000000, 'Fr': 223.000000, 'Ra': 226.000000, 'Ac': 227.000000, 'Th': 232.038100, 'Pa': 231.035880, 'U': 238.028910, 'Np': 237.000000, 'Pu': 244.000000, 'Am': 243.000000, 'Cm': 247.000000, 'Bk': 247.000000, 'Cf': 251.000000, 'Es': 252.000000, 'Fm': 257.000000, 'Md': 258.000000, 'No': 259.000000, 'Lr': 262.000000, 'Rf': 261.000000, 'Db': 262.000000, 'Sg': 266.000000, 'Bh': 264.000000, 'Hs': 277.000000, 'Mt': 268.000000, 'Ds': 281.000000, 'Rg': 272.000000, 'Cn': 285.000000, 'Uuq': 289.000000, 'Uuh': 292.000000 }