00001
00002
00003 """
00004
00005 ScrumPy -- Metabolic Modelling with Python
00006
00007 Copyright Mark Poolman 1995 - 2002
00008
00009 This file is part of ScrumPy.
00010
00011 ScrumPy is free software; you can redistribute it and/or modify
00012 it under the terms of the GNU General Public License as published by
00013 the Free Software Foundation; either version 2 of the License, or
00014 (at your option) any later version.
00015
00016 ScrumPy is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 GNU General Public License for more details.
00020
00021 You should have received a copy of the GNU General Public License
00022 along with ScrumPy; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00024
00025 """
00026
00027 """
00028 M.G.Poolman 2001
00029 Kinetic.Model - a user level interface to kinetic models
00030 """
00031
00032
00033 import os,sys, random, exceptions
00034
00035 from BasicInfo import Location, HeaderPath
00036 from Data import DataSets
00037 from Util import File,Seq,Set
00038
00039
00040 import ScrumPy
00041 import LowLevelKinMod, CGen
00042
00043 gui=None
00044
00045 """
00046 Things relevant to user (treat as ReadOnly !!)
00047 """
00048
00049
00050 Param = LowLevelKinMod.Param
00051 Conc = LowLevelKinMod.Conc
00052 Vel = LowLevelKinMod.Vel
00053 dMet = LowLevelKinMod.dMet
00054
00055
00056
00057
00058 TimeString = "Time"
00059
00060
00061 LowLevel = LowLevelKinMod.LowLevelKinMod
00062
00063 ErrMsgTitle = "ScrumPy error"
00064
00065
00066 class Monitor(DataSets.DataSet):
00067
00068 def __init__(self, model, Params=[], UpdateIfNotOK="Ignore"):
00069
00070 if Params==[]:
00071 Params = model.GetVecNames(Param)
00072
00073 self.model=model
00074 self.VarNames = ["Time"] + model.sm.cnames + model.sm.rnames
00075 self.Params = Params[:]
00076 self.UpdateIfNotOK=UpdateIfNotOK
00077
00078 ItemNames = self.VarNames+Params
00079
00080 DataSets.DataSet.__init__(self, ItemNames=ItemNames, SrcDic=model)
00081
00082
00083 def Update(self):
00084
00085 if self.model.IsOK() or self.UpdateIfNotOK=="Yes":
00086 DataSets.DataSet.Update(self)
00087 elif self.UpdateIfNotOK=="Zero":
00088 vars = [0]*len(self.VarNames)
00089 pars = self.model.GetVals(self.Params)
00090 self.NewRow(vars+pars)
00091 elif self.UpdateIfNotOK!="Ignore":
00092 raise exceptions.ValueError, "Unknown value "+self.UpdateIfNotOK+" for UpdateIfNotOK"
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 def DefaultSimMon(Model, DataSet=None):
00107 pass
00108
00109
00110 from LP import Array
00111 class DoubleArray(Array.BaseArray):
00112 _del = LowLevelKinMod.delete_doubleArray
00113 _get = LowLevelKinMod.doubleArray_getitem
00114 _set = LowLevelKinMod.doubleArray_setitem
00115 _new = LowLevelKinMod.new_doubleArray
00116 _cast = float
00117 _offset=0
00118
00119 def _NoDel(self):
00120 pass
00121
00122 def __init__(self,src=None, length=None, NoDel=False):
00123
00124 if src == length == None:
00125 raise exceptions.ValueError, "src and length can't both be None"
00126
00127 if src == None:
00128 Array.BaseArray.__init__(self, length)
00129
00130 elif type(src) == list:
00131 Array.BaseArray.__init__(self, src)
00132
00133 else:
00134 self._array = src
00135 self.size = length
00136
00137 if NoDel:
00138 self._del = self._NoDel
00139
00140
00141
00142
00143 class Model (LowLevel):
00144 """ instances of this class are the ScrumPy modellers main tool.
00145 House keeping methods are at the begining, user methods at the end
00146 """
00147 def __init__(self):
00148
00149
00150 LowLevel.__init__(self)
00151 self.Sim = LowLevel.Simulate
00152
00153
00154 self.SimSSRetry = 4
00155 self.SimSSPoints = 128
00156 self.SimSSTincr = 0.125
00157 self.SimSSGrowth = 1.5
00158 self.NSteps = 1
00159
00160 self.SSTol = 1e-5
00161
00162 self.BuildKinetic()
00163
00164
00165
00166 def BuildKinetic(self):
00167
00168 ModelDesc = self.ModelDesc
00169 SrcFName = self.FileName+".c"
00170 self.MakeC(open(SrcFName,"w"))
00171
00172 SoFName = self.FileName+".so"
00173 BuildSo ="g++ -fPIC -shared -I " + HeaderPath + " -o " + SoFName + " " + SrcFName
00174 syserr = os.system(BuildSo)
00175 if syserr:
00176 gui.ErrorMsg("Failed to compile "+ self.ModelName +"\nsee Python terminal and stderr for clues")
00177 print "!!! ", BuildSo, " generated error ", str(syserr), "!!!\n"
00178
00179 else:
00180 if not File.IsAbsPath(SoFName):
00181 SoFName = os.curdir + os.sep + SoFName
00182 LowLevel.Load(self, self.ModelName,SoFName)
00183
00184
00185
00186 self.ZerVec(Conc)
00187 self.NaNVec(Param)
00188
00189 ConsDic = ModelDesc.ConsDic
00190 nCons = len(ConsDic)
00191 if nCons >0:
00192 ParamNames = self.GetVecNames(Param)[:-nCons]
00193 else:
00194 ParamNames = self.GetVecNames(Param)
00195
00196 IniDic = ModelDesc.InitDic
00197 IniNames = IniDic.keys()
00198 for Name in IniNames:
00199 self[Name] = IniDic[Name]
00200
00201 self.InitCSums()
00202
00203 Seq.RemoveFrom(ParamNames, IniNames)
00204 if len(ParamNames) > 0:
00205 gui.WarnMsg("Parameters not initialised" + str(ParamNames))
00206
00207 MetNames = self.GetVecNames(Conc)
00208 Seq.RemoveFrom(MetNames, IniNames)
00209 if len(MetNames) > 0:
00210 gui.WarnMsg("Metabolites not initialised" + str(MetNames))
00211
00212
00213 self.Eval()
00214 self.ResetInteg()
00215 self.SetRescue()
00216
00217
00218 def ConsDic(self):
00219
00220 cm = self.ConsMoieties(self)
00221 for c in cm.cnames:
00222 cm.DelRow(c)
00223 return cm.ToColDict()
00224
00225
00226
00227
00228
00229
00230 def MakeC(self, out):
00231 md = self.ModelDesc
00232 sm = self.sm
00233 md.ConsDic = self.ConsDic()
00234 cons = md.ConsDic.keys()
00235 md.conpard = conpard = {}
00236 conparl = []
00237 for con in cons:
00238 self.sm.MakeLastRow(con)
00239 self.smexterns.MakeLastRow(con)
00240 conp = "CSUM_"+con
00241 conpard[con] = conp
00242 conparl.append(conp)
00243
00244
00245 md.Params = self.ParamNames = Set.Complement(md.IdList, sm.rnames+sm.cnames) + conparl
00246
00247 out.write(CGen.Preamble)
00248 out.write("static double "+self.ModelName+"Time ; \n")
00249 out.write(CGen.VecDecls(md))
00250 out.write(CGen.Enums(md))
00251 out.write(CGen.NameArrays(md))
00252 out.write(CGen.DiffEqns(md))
00253 out.write(CGen.RateEqns(md))
00254 out.write(CGen.ConsEqns(md))
00255 out.write(CGen.Struct(md))
00256
00257
00258
00259 def InitCSums(self):
00260
00261 ConsDic = self.ModelDesc.ConsDic
00262 conpard = self.ModelDesc.conpard
00263
00264 for k in ConsDic.keys():
00265 sum = self[k]
00266 tuplist = ConsDic[k]
00267 for tup in tuplist:
00268 sum += float(self[tup[0]]) * float(tup[1])
00269
00270 self[conpard[k]] = sum
00271
00272
00273
00274
00275 def Eval(self, *args):
00276 LowLevel.Eval(self)
00277
00278
00279 def __del__(self):
00280 self.Destroy()
00281
00282 def Destroy(self):
00283 LowLevel.Destroy(self)
00284
00285
00286
00287
00288
00289 def __getitem__(self, name):
00290 return self.GetVal(name)
00291
00292 def __setitem__(self, name, val):
00293 self.SetVal(name, val)
00294
00295 def ReportBadPoints(self, Source, Points):
00296 """ do something gui at a later date """
00297
00298
00299 print "BadPoints from ", Source, ":\n", Points
00300
00301
00302
00303
00304
00305
00306 def GetVals(self, names):
00307 """ pre: names is a list of strings
00308 post: returns a list of the values of names """
00309
00310 rv = []
00311 for n in names:
00312 rv.append(self[n])
00313
00314 return rv
00315
00316 def SetVals(self, names, vals):
00317 """ pre: names is a list of strings, vals is a list of float,
00318 len(names) == len (vals)
00319 post: GetVals(names) == vals"""
00320
00321 for i in range(len(names)):
00322 self[names[i]] = vals[i]
00323
00324
00325 def SetTime(self, time):
00326 """pre: time <=0.0
00327 post: self["Time"] == time
00328 NB: this ensures internal consistancy in the C library when time is changed.
00329 m["Time"] = t is best avoided."""
00330
00331 self["Time"] = time
00332 self.ResetInteg()
00333
00334
00335
00336
00337
00338
00339 def GetVec(self,code):
00340 """ return a list of values of the vector associated with code """
00341
00342 return DoubleArray(LowLevel.GetVec(self, code), LowLevel.SizeVec(self, code),NoDel=True)
00343
00344 def SetVec(self, code, Vec):
00345 """ pre: len(Vec) == self.SizeVec(code), type(Vec[0..len(Vec)-1] == float
00346 post: Vec == self.GetVec(code) """
00347
00348 return self.SetVals(self.GetVecNames(code),Vec)
00349
00350 def GetVecNames(self, code):
00351 """ return a list of names of the values of the vector associated with code """
00352 vec = {
00353 Conc: self.sm.rnames,
00354 Vel: self.sm.cnames,
00355 Param:self.ParamNames}[code]
00356 return vec[:]
00357
00358
00359 def GetAllNames(self):
00360 """ return a list (of strings) of all identifiers in the model """
00361 return(
00362 self.GetVecNames(Vel) +
00363 self.GetVecNames(Conc) +
00364 self.GetVecNames(Param) +
00365 [TimeString]
00366 )
00367
00368 def keys(self):
00369 return self.GetAllNames()
00370 """
00371 because models anyway have dictionary-like characteristics we supply
00372 a keys function for completeness. This is useful for the monitor
00373 classes which can then be updated from any dicionary-like instance
00374 """
00375
00376
00377 def Randomise(self, lorel=0.5, hirel=0.5, *args, **kwargs):
00378
00379 for name, val in self.ModelDesc.InitDic.items():
00380 self[name] = value * ( 1+random.uniform(-lorel, hirel))
00381
00382 self.InitCSums()
00383 self.Eval()
00384 self.ResetInteg()
00385
00386
00387 def PingConc(self, pert=1e-6):
00388 """ perturb all concentrations by multiplying by a random number [1-pert..1+pert]"""
00389
00390 concs = self.GetVec(Conc)
00391 for c in range(len(concs)):
00392 concs[c] *= random.uniform(1-pert,1+pert)
00393
00394
00395
00396
00397 def FindSS(self, Retry=100):
00398 """ Use a combination of simulation and Newton to (attempt to) obtain a steady-state"""
00399
00400 curtime =self["Time"]
00401
00402 self.Eval()
00403
00404 while self.GetSSErr() > self.SSTol *2 and Retry >0:
00405 self.Sim(self,1)
00406 Retry-=1
00407 self.NewtSS()
00408
00409 self.SetTime(curtime)
00410
00411
00412
00413 def PureSimSS(self, MaxSteps=100):
00414 """ Attempt to get to steady-state using only time course simulation """
00415
00416 print "!! Deprecated PureSimSS() !!"
00417
00418 self.SimToSS(MaxSteps, self.SSTol)
00419
00420
00421 def ScaledSensits(self, pname, Vars, Scaled=True, SS=True, Pert=1e-3):
00422
00423 if SS:
00424 def Eval():
00425 self.PingConc()
00426 self.FindSS()
00427
00428
00429 else:
00430 Eval = self.CalcVels
00431
00432 pval = self[pname]
00433 delta_p = pval*Pert
00434 TwodP = 2 * delta_p
00435
00436 if Scaled:
00437 Eval()
00438 midvars = self.GetVals(Vars)
00439
00440 self[pname] += delta_p
00441 Eval()
00442 hivars = self.GetVals(Vars)
00443
00444 self[pname] -= TwodP
00445 Eval()
00446 lovars = self.GetVals(Vars)
00447
00448 self[pname] = pval
00449
00450 dydx = map(lambda yh, yl:(yh-yl)/(TwodP), hivars, lovars)
00451 if Scaled:
00452 dydx = map(lambda d, y:d*pval/y, dydx, midvars)
00453
00454 return dydx
00455
00456
00457
00458
00459
00460 def NewDataSet(self,Params=[],UpdateIfNotOK="Ignore"):
00461 """ UpdateIfNotOK == "Ignore" => only update if self.IsOK()
00462 "Zero" => update vars with [0,0..] but update Params if not self.IsOK()
00463 "Yes" => Always update"""
00464
00465
00466 ds = Monitor(self,[],UpdateIfNotOK)
00467 ds.MakeFirstCol("Time")
00468 return ds
00469
00470
00471
00472 def SetFromDataSet(self, ds, n):
00473 """ pre: n is an integer 0 <= n < len(ds)
00474 post: values of ds.keys() in self updated from the nth record of ds """
00475
00476 for k in ds.cnames:
00477 self[k] = ds[k][n]
00478
00479
00480
00481 def GetStateSaver(self):
00482 """ returns a StateSaver instance """
00483
00484
00485 class StateSaver(DataSets.DataSet):
00486 raise "Kinetic.Model.Model.StateSaver", "needs re-writing - DataSet API changed"
00487
00488 def __init__(self, model):
00489 self.names = [TimeString]
00490 for comp in [Conc, Vel, Param]:
00491 self.names = self.names+ model.GetVecNames(comp)
00492
00493 self.model = model
00494 DataSets.DataSet.__init__(self, FromFile=0, NameList=self.names)
00495
00496
00497
00498
00499 def SaveFile(self, fname=None):
00500 DataSets.DataSet.SaveFile(self, fname=fname, InOrder=self.names)
00501
00502 return StateSaver(self)
00503
00504
00505 def GetState(self):
00506 rv = {}
00507 rv["Time"] = self["Time"]
00508 for vec in [ScrumPy.Conc, ScrumPy.Vel, ScrumPy.Param]:
00509 rv[vec] = self.GetVec(vec)
00510 return rv
00511
00512
00513
00514 def SetFromState(self, state):
00515 """ pre: state = m.GetState(), self = m """
00516
00517 self["Time"] = state["Time"]
00518 for vec in [ScrumPy.Conc, ScrumPy.Vel, ScrumPy.Param]:
00519 self.SetVec(vec, state[vec])