00001
00002 """
00003
00004 ScrumPy -- Metabolic Modelling with Python
00005
00006 Copyright Mark Poolman 1995 - 2002
00007
00008 This file is part of ScrumPy.
00009
00010 ScrumPy is free software; you can redistribute it and/or modify
00011 it under the terms of the GNU General Public License as published by
00012 the Free Software Foundation; either version 2 of the License, or
00013 (at your option) any later version.
00014
00015 ScrumPy is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018 GNU General Public License for more details.
00019
00020 You should have received a copy of the GNU General Public License
00021 along with ScrumPy; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00023
00024 """
00025
00026
00027 import sys, exceptions
00028
00029
00030 from Util import Seq, DynMatrix, Set, Types,Tree
00031 from Structural import StoMat, EnzSubset, ReacTree
00032 from Parser import lexer
00033 import ElModes
00034
00035 BadElMsg="""
00036 !! Element types of stoichiometry matrix !!
00037 !! *MUST* be arbitrary rational !!
00038 !! Giving up. !!
00039 """
00040
00041 def SMFromDesc(Desc):
00042
00043 ElType = Desc.OptDic["ElType"]
00044 StoDic = Desc.StoDic
00045 MetList =Desc.MetList
00046
00047 sm = StoMat.StoMat(
00048 cnames=StoDic.keys(),
00049 rnames=MetList[:],
00050 Conv=ElType
00051 )
00052
00053 for reac in sm.cnames:
00054 sto = StoDic[reac]
00055 sm.SetSto(reac, sto)
00056
00057 return sm
00058
00059
00060 class Model:
00061
00062 def Destroy(self):
00063 pass
00064
00065 def BuildStructural(self):
00066 """pre: ModelDesc is correctly filled in instance of ScrumPy.Parser.Parser.ModelDescriptor """
00067
00068 ModelDesc = self.ModelDesc
00069
00070 self.smexterns = SMFromDesc(ModelDesc)
00071 ExtList = ModelDesc.ExtList[:]
00072 if ModelDesc.OptDic["AutoExtern"]:
00073 ExtList = Set.Union(ExtList,self.smexterns.Unbals())
00074
00075 self.sm = self.smexterns.Copy()
00076 for e in ExtList:
00077 try:
00078 self.sm.DelRow(e)
00079 except:
00080 sys.stderr.write("! Warning: "+e+" declared external, but not used !\n")
00081
00082 self.sm.Externs = ExtList[:]
00083 self.smexterns.Externs = ExtList[:]
00084 if ModelDesc.OptDic["DeQuote"]:
00085 self.sm.DeQuote()
00086 self.smexterns.DeQuote()
00087
00088 self.sm.Irrevs = self.sm.GetIrrevs()
00089 self.smexterns.Irrevs = self.sm.GetIrrevs()
00090
00091 self.RemoveUnused()
00092
00093
00094
00095
00096
00097 def DelReactions(self,Reactions):
00098 """ pre: Reactions is a list of strings
00099 post: reactions removed from self """
00100 for r in Reactions:
00101 if not r in self.sm.cnames:
00102 sys.stderr.write("Warning: tried to delete non-existent reaction, " + r + "\n")
00103 else:
00104 self.sm.DelReac(r)
00105 self.smexterns.DelReac(r)
00106
00107
00108 self.sm.ZapZeroes()
00109 self.smexterns.ZapZeroes()
00110 self.smexterns.Externs = Set.Intersect(self.smexterns.Externs, self.smexterns.rnames)
00111 self.sm.Externs = self.smexterns.Externs[:]
00112
00113
00114 def AddReactions(self, StoDicDic):
00115 print "ScrumPy.Structural.Model.AddReactions due for removal"
00116 for reac in StoDicDic.keys():
00117 sto = StoDicDic[reac].copy()
00118 self.smexterns.NewReaction(reac, sto)
00119 for met in sto.keys():
00120 if met in self.sm.Externs:
00121 del(sto[met])
00122 self.sm.NewReaction(reac, sto)
00123
00124
00125
00126
00127 def RemoveUnused(self):
00128
00129 Unused = Set.Complement(self.smexterns.cnames, self.sm.cnames)
00130
00131 if len(Unused) >0:
00132 print "The following reactions affect no internal metabolites, removing them:\n",Unused
00133 for u in Unused:
00134 if u in self.smexterns.cnames:
00135 self.smexterns.DelCol(u)
00136 if u in self.sm.cnames:
00137 self.sm.DelCol(u)
00138
00139
00140
00141 def IsIrrev(self, name):
00142 """pre: name is a reaction name
00143 post: self.IsIrrev(name) => name is an irreversible reaction """
00144
00145 return self.sm.IsIrrev(name)
00146
00147
00148 def NetSto(self,vels):
00149 "return a matrix of the net stoichs represented by the rate information in vels"
00150
00151 rv = DynMatrix.matrix()
00152 sm = self.smexterns.ToNumPyMtx(conv=int)
00153 v = vels.ToNumPyMtx(conv=int)
00154 res = sm * v
00155 rv.FromNumPyMtx(res)
00156 rv.rnames = self.smexterns.rnames
00157 rv.cnames = vels.cnames
00158 return rv
00159
00160
00161 def Externals(self):
00162 return Set.Complement(self.smexterns.rnames, self.sm.rnames)
00163
00164 def Transporters(self,NamesOnly=False):
00165 seen = {}
00166 rv = []
00167 exs = self.Externals()
00168 for e in exs:
00169 for tx in self.smexterns.InvolvedWith(e):
00170 if not seen.has_key(tx):
00171 seen[tx] = 1
00172 rv.append([tx, Set.Intersect(exs,self.smexterns.Reactants(tx))])
00173
00174 if NamesOnly:
00175 return seen.keys()
00176 return rv
00177
00178
00179 def FindIsoforms(self):
00180 stodic = {}
00181 for reac in self.smexterns.cnames:
00182 strsto = str(self.smexterns.InvolvedWith(reac))
00183 if stodic.has_key(strsto):
00184 stodic[strsto].append(reac)
00185 else:
00186 stodic[strsto] = [reac]
00187 rv = []
00188 for reac in stodic.values():
00189 if len(reac)>1:
00190 rv.append(reac)
00191
00192 return rv
00193
00194
00195 def DelIsoforms(self):
00196 isos = self.FindIsoforms()
00197 rv = {}
00198 for iso in isos:
00199 rv[iso[0]] = iso[1:]
00200 for reac in iso[1:]:
00201 self.sm.DelReac(reac)
00202 self.smexterns.DelReac(reac)
00203 return rv
00204
00205
00206 def FindOrphans(self):
00207 raise DeprecationWarning, "use model.OrphanMets() instead"
00208
00209
00210 def OrphanMets(self):
00211 return self.smexterns.OrphanMets()
00212
00213
00214 def Core(self):
00215 """ pre: True
00216 post: A copy of the external stoichiometry matrix with all internal orphans
00217 and associated reactions removed. """
00218
00219 if self.smexterns.IsDeQuoted():
00220 self.smexterns.ReQuote()
00221 smx = self.Core()
00222 self.smexterns.DeQuote()
00223 smx.DeQuote()
00224 else:
00225 smx = self.smexterns.Copy()
00226 orphans = Set.Complement(smx.OrphanMets(), smx.Externs)
00227 while len(orphans) > 0:
00228 print "len(o)", len(orphans)
00229 for met in orphans:
00230 if not met in smx.Externs:
00231 for rn in smx.InvolvedWith(met):
00232 smx.DelReac(rn)
00233 smx.DelRow(met)
00234
00235 smx.ZapZeroes()
00236 orphans = Set.Complement(smx.OrphanMets(), smx.Externs)
00237
00238 return smx
00239
00240
00241 def DeadReactions(self):
00242 rv = []
00243 k = self.sm.NullSpace()
00244 for r in k.rnames:
00245 if Seq.AllEq(k[r],0):
00246 rv.append(r)
00247 return rv
00248
00249 def DisconnectsK(self, thresh=1e-6,exts=False):
00250 """ pre: True
00251 post: return list of lists of disconnected subsystems by null-space analysis of self.sm
00252 exts => use the external stoichiometry matrix
00253 first item is possible empty list of dead reactions
00254 """
00255 if exts:
00256 k = self.smexterns.OrthNullSpace()
00257 else:
00258 k = self.sm.OrthNullSpace()
00259 deads = []
00260 for reac in k.rnames[:]:
00261 if Seq.AllMatch(k[reac], lambda x:abs(x)<thresh):
00262 deads.append(reac)
00263 k.DelRow(reac)
00264 return k.NonZeroR([deads],thresh)
00265
00266
00267 def MaxCycles(self):
00268 return self.DisconnectsK(exts=1)[1:]
00269
00270
00271
00272
00273
00274 def EnzSubsets(self):
00275 """ pre: True
00276 post: return EnzSubset.EssDic(self)
00277 see EnzSubset module for details
00278 """
00279
00280 return EnzSubset.EssDic(self)
00281
00282
00283
00284 def ElModes(self):
00285
00286 ssm, sm, smx = self.EnzSubsets().CondensedSMs()
00287 if len(ssm.cnames) <2:
00288 elmodes = ssm
00289 stos = smx
00290 else:
00291 ems = ElModes.GetElModes(sm)
00292
00293 elmodes = ssm.Mul(ems)
00294
00295 return ElModes.ModesDB(elmodes,self)
00296
00297
00298
00299 def ConsMoieties(self,raise_err=True):
00300
00301 smt = self.sm.Copy(tx = 1)
00302 ksmt = smt.NullSpace()
00303 deps = []
00304 for c in ksmt.cnames:
00305 for r in ksmt.rnames:
00306 if ksmt[r,c] != 0 and Seq.NumOfMatches(ksmt[r], lambda x: x!=0) ==1:
00307 deps.append(r)
00308 break
00309
00310 if len(deps) != len(ksmt.cnames):
00311 print "! missed deps should have", len(smtk.cnames), "found", len(deps)
00312 if raise_er:
00313 raise exceptions.ValueError, str(len(smtk.cnames)-len(deps)) + "missing dependencies"
00314
00315 for d in deps:
00316 ksmt.MakeFirstRow(d)
00317 c = deps.index(d)
00318 val = ksmt[0,c]
00319 ksmt.cnames[c] = d
00320 ksmt.DivCol(c,k=val)
00321
00322
00323 return ksmt
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 def ReacTree(self):
00344
00345 def diff(a,b):
00346 return 1- abs(Seq.CosTheta(a,b))
00347
00348 k = self.sm.OrthNullSpace()
00349 rdm = k.RowDiffMtx(diff)
00350 t= rdm.ToNJTree()
00351 t.rdm = rdm
00352 return t