• Main Page
  • Namespaces
  • Classes
  • Files
  • File List

/home/mark/model/software/ScrumPy/ScrumPy/Kinetic/Model.py

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 #from ScrumPy import gui
00039 
00040 import ScrumPy
00041 import LowLevelKinMod, CGen
00042 
00043 gui=None  # must be set by importing module
00044 #TODO - remove gui from here, report errors etc back to calling functions
00045 """
00046 Things relevant to user (treat as ReadOnly !!)
00047 """
00048 
00049 # these 4 define valid values for the "code" argument to GetVec and GetNameVec
00050 Param = LowLevelKinMod.Param
00051 Conc = LowLevelKinMod.Conc
00052 Vel = LowLevelKinMod.Vel
00053 dMet = LowLevelKinMod.dMet
00054 
00055 
00056 
00057 # a string representing time, avoids use of literals in code
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         #else do nothing
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106 def DefaultSimMon(Model, DataSet=None):
00107     pass
00108 
00109 #TODO this needs moving into Util for both LP and Kinetic (and anything else thatmightr want it
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   # a convenient handle  on the low level simulate when we overload it
00152 
00153 
00154         self.SimSSRetry = 4
00155         self.SimSSPoints = 128
00156         self.SimSSTincr = 0.125
00157         self.SimSSGrowth = 1.5
00158         self.NSteps = 1 # no of sim steps on last simulation
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):                 # because dlib/ld.so need absolute path names
00181                 SoFName = os.curdir + os.sep + SoFName
00182             LowLevel.Load(self, self.ModelName,SoFName)
00183 
00184             # we've generated, compiled and loaded the model, now to initialise it
00185 
00186             self.ZerVec(Conc)       # it's OK to init concentrations to zero by default
00187             self.NaNVec(Param)    # but not parameters, this ensures the user *will* find out
00188 
00189             ConsDic = ModelDesc.ConsDic
00190             nCons = len(ConsDic)
00191             if nCons >0:
00192                 ParamNames = self.GetVecNames(Param)[:-nCons] # we will generate conservation params later
00193             else:
00194                 ParamNames = self.GetVecNames(Param)
00195 
00196             IniDic = ModelDesc.InitDic
00197             IniNames = IniDic.keys() # initialise values as supplied in the Ini dictionary
00198             for Name in IniNames:
00199                 self[Name] = IniDic[Name]
00200 
00201             self.InitCSums()  # sort out values for conserved totals
00202 
00203             Seq.RemoveFrom(ParamNames, IniNames)  # see which params are not initialised
00204             if len(ParamNames) > 0:
00205                 gui.WarnMsg("Parameters not initialised" + str(ParamNames))
00206 
00207             MetNames = self.GetVecNames(Conc)
00208             Seq.RemoveFrom(MetNames, IniNames)  # see which mets are not initialised
00209             if len(MetNames) > 0:
00210                 gui.WarnMsg("Metabolites not initialised" + str(MetNames))
00211 
00212 
00213             self.Eval()     # initialise velocities and dependent mets
00214             self.ResetInteg() # ensure integrator has correct start values
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             #CGen.InitMD(md)
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): # just ignore 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        ### User methods start here  ################
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         #return self.GetVals(self.GetVecNames(code))
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) # restore time to starting pos.
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         # not a lot of point given current FindSS()
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                 #if not self.IsOK():
00428                 #    print "!!"
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)   # mid of 3 point differential
00439 
00440         self[pname] += delta_p
00441         Eval()
00442         hivars = self.GetVals(Vars)         # high point of 3 point diff
00443 
00444         self[pname] -= TwodP
00445         Eval()
00446         lovars = self.GetVals(Vars)         # low point of 3 point diff
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         #TODO: specify whether static or dynamic here also
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             #def Update(self):
00497             #    self.model.UpdateDataSet(self)
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])

Generated on Tue Sep 4 2012 15:38:01 for ScrumPy by  doxygen 1.7.1