runSolver.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. import ivp
  2. import os
  3. import cModel
  4. import sys
  5. import json
  6. import numpy
  7. import time
  8. import scipy.interpolate
  9. defaultValues={\
  10. 'method':'LSODA',\
  11. 'atol':1e-4,\
  12. 'rtol':1e-4,\
  13. 't0':0,\
  14. 'tmax':1,\
  15. 'mode':'IVPSimultaneous',\
  16. 'nt':201,
  17. 'tUnit':'day',\
  18. 'network':'labkey-klimt.json',\
  19. 'startFromRef':'None',\
  20. 'project':'Analysis/Run',\
  21. 'schema':'lists',\
  22. 'query':'runs',\
  23. 'view':'withStrings'}
  24. def get(setup,par):
  25. try:
  26. return setup[par]
  27. except KeyError:
  28. pass
  29. return defaultValues[par]
  30. def parseSetup(setupFile):
  31. with open(setupFile,'r') as f:
  32. setup=json.load(f)
  33. out={}
  34. for p in defaultValues:
  35. out[p]=get(setup,p)
  36. #q=[x if not x in out for x in setup]
  37. q=[x for x in setup if not x in out]
  38. for x in q:
  39. out[x]=setup[x]
  40. return out
  41. def getScale(setup):
  42. tUnit=setup['tUnit']
  43. return convertUnit(tUnit)
  44. def convertUnit(tUnit):
  45. if tUnit=='min':
  46. return 1
  47. if tUnit=='hour':
  48. return 60
  49. if tUnit=='day':
  50. return 24*60
  51. if tUnit=='month':
  52. return 24*60*30
  53. if tUnit=='year':
  54. return 24*60*365
  55. return 1
  56. def getStrides(setup):
  57. tmax=setup['tmax']*convertUnit(setup['tUnit'])
  58. t0=setup['t0']
  59. try:
  60. stride=setup['stride']
  61. except KeyError:
  62. return [{'label':'','length':tmax-t0}]
  63. #cover tmax with steps of length stride['length']
  64. strides=[]
  65. strideLength=stride['length']*convertUnit(stride['tUnit'])
  66. i=0
  67. while t0<tmax:
  68. strides.append({'length':strideLength,'label':'_step{:03d}'.format(i)})
  69. t0+=strideLength
  70. i+=1
  71. return strides
  72. def getFiles(setup, getAll=False):
  73. strides=getStrides(setup)
  74. readable=['t','sol','se','qt','sOut']
  75. #get last stride
  76. steps=[strides[-1]]
  77. if getAll:
  78. steps=strides
  79. inFiles=[]
  80. for s in steps:
  81. l=s['label']
  82. inFiles.append({x:'{}{}.txt'.format(x,l) for x in readable})
  83. return inFiles
  84. def main(parFiles,jobDir,startDir='NONE'):
  85. model=cModel.model()
  86. setupFile=parFiles[0]
  87. modelFile=parFiles[1]
  88. parameterFile=parFiles[2]
  89. model.parse(modelFile,parameterFile)
  90. setup=parseSetup(setupFile)
  91. scale=getScale(setup)
  92. tmax=setup['tmax']*scale
  93. print('Using {}'.format(jobDir))
  94. if startDir!='NONE':
  95. print('Using solution from {}'.format(startDir))
  96. t0,y0,s0,lut,lutSE=getStartPointFromDir(startDir)
  97. print('t0={}'.format(t0))
  98. else:
  99. t0,y0,s0,lut,lutSE=getStartPoint(setup)
  100. #we should reorder S1 to match model.lutSE
  101. #S1 is nxm, so we should reorder columns
  102. sIn=numpy.zeros(s0.shape)
  103. if s0.size>0:
  104. for x in model.lutSE:
  105. #this could be modified for different ordering of lut as well
  106. sIn[:,model.lutSE[x]]=s0[:,lutSE[x]]
  107. #copy t0 to setup to help get the strides right
  108. setup['t0']=t0
  109. strides=getStrides(setup)
  110. for step in strides:
  111. t1=t0+step['length']
  112. start_time=time.time()
  113. if setup['mode']=='SequentialOdeint':
  114. t,sol,se,s1=ivp.solveSequentialOdeint(model,t1,setup['nt'],t0,y0,sIn)
  115. if setup['mode']=='SimultaneousOdeint':
  116. t,sol,se,s1=ivp.solveSimultaneousOdeint(model,t1,setup['nt'],t0,y0,sIn)
  117. if setup['mode']=='IVP':
  118. t,sol,se,s1=ivp.solveSequential(model,t1,\
  119. nt=setup['nt'],\
  120. atol=setup['atol'],\
  121. rtol=setup['rtol'],method=setup['method'],\
  122. t0=t0,y0=y0,sIn=sIn)
  123. if setup['mode']=='IVPSimultaneous':
  124. t,sol,se,s1=ivp.solveSimultaneous(model,t1,\
  125. nt=setup['nt'],\
  126. atol=setup['atol'],\
  127. rtol=setup['rtol'],method=setup['method'],\
  128. t0=t0,y0=y0,sIn=sIn)
  129. end_time=time.time()
  130. #interpolate on s1
  131. #s1 has shape ft x n x m
  132. #where ft is LSODE driven number of points
  133. qt,sOut=interpolate(setup,model,t,s1,t0,t1)
  134. print('Time: {:.3f} s'.format(end_time-start_time))
  135. y0=sol[-1]
  136. t0=t[-1]
  137. sIn=sOut[-1]
  138. #store
  139. writeable={'t':t,'sol':sol,'se':se,'qt':qt,'sOut':sOut}
  140. l=step['label']
  141. writeable={os.path.join(jobDir,'{}{}.txt'.format(x,l)):writeable[x]\
  142. for x in writeable}
  143. for x in writeable:
  144. if x.find('sOut')>-1:
  145. write3D(x,writeable[x],model.lut,model.lutSE)
  146. else:
  147. numpy.savetxt(x,writeable[x])
  148. print('Completed step {}'.format(l))
  149. print('Completed run')
  150. #update setup with new content (particularly t0)
  151. setupOut=os.path.join(jobDir,'setup.json')
  152. with open(setupOut,'w+') as f:
  153. f.write(json.dumps(setup))
  154. #this is 3D, so new routines
  155. def interpolate(setup,model,t,s1,t0,tmax):
  156. #interpolate on s1
  157. #s1 has shape ft x n x m
  158. #where ft is LSODE driven number of points
  159. sOut=numpy.zeros((setup['nt'],model.n,model.m))
  160. qt=numpy.linspace(t0,tmax,setup['nt'])
  161. for i in range(model.n):
  162. for j in range(model.m):
  163. y=s1[:,i,j]
  164. f = scipy.interpolate.interp1d(t, y, kind='cubic')
  165. sOut[:,i,j]=f(qt)
  166. return qt,sOut
  167. def invertLUT(lut):
  168. fcode=[None]*len(lut)
  169. for x in lut:
  170. fcode[lut[x]]=x
  171. return fcode
  172. def write3D(fName,a,lut,lutSE):
  173. with open(fName,'w') as f:
  174. f.write('#Shape {}\n'.format(a.shape))
  175. f.write('#Lut {}\n'.format(invertLUT(lut)))
  176. f.write('#Lut (SE) {}\n'.format(invertLUT(lutSE)))
  177. i=0
  178. for data_slice in a:
  179. f.write('#\t Slice {}\n'.format(i))
  180. numpy.savetxt(f,data_slice)
  181. i+=1
  182. def parseLUT(line,isSE=False):
  183. SE=''
  184. if isSE:
  185. SE='(SE)'
  186. header='#Lut {}'.format(SE)
  187. names=line.replace(header,'').\
  188. replace('[','').\
  189. replace(']','').\
  190. replace(' ','').\
  191. replace('\n','').\
  192. replace("'",'').\
  193. split(',')
  194. lut={names[i]:i for i in range(len(names))}
  195. return lut
  196. def parseShape(line):
  197. shape=line.replace('#Shape ','').\
  198. replace('\n','').\
  199. replace('(','').\
  200. replace(')','').\
  201. split(',')
  202. return [int(x) for x in shape]
  203. def read3D(fName):
  204. new_data=numpy.loadtxt(fName)
  205. #read and parse first three lines to get shape,lut and lutSE
  206. nLines=3
  207. with open(fName,'r') as f:
  208. lines=[f.readline() for i in range(nLines)]
  209. shape=parseShape(lines[0])
  210. lut=parseLUT(lines[1])
  211. lutSE=parseLUT(lines[2],isSE=True)
  212. return new_data.reshape(shape),lut,lutSE
  213. def loadSolutionFromRef(setup, loadAll=False):
  214. if setup['startFromRef']=='None':
  215. return 0,numpy.array([]),numpy.array([]),numpy.array([]),numpy.array([])
  216. nixSuite=os.path.join(os.path.expanduser('~'),'software','src','nixSuite')
  217. sys.path.append(os.path.join(nixSuite,'wrapper'))
  218. import nixWrapper
  219. nixWrapper.loadLibrary('labkeyInterface')
  220. import labkeyInterface
  221. import labkeyFileBrowser
  222. #import labkeyDatabaseBrowser
  223. net=labkeyInterface.labkeyInterface()
  224. fconfig=os.path.join(os.path.expanduser('~'),'.labkey',setup['network'])
  225. net.init(fconfig)
  226. #debug
  227. net.getCSRF()
  228. #db=labkeyDatabaseBrowser.labkeyDB(net)
  229. fb=labkeyFileBrowser.labkeyFileBrowser(net)
  230. ref=setup['startFromRef']
  231. #refFilter={'variable':'runRef','value':ref,'oper':'eq'}
  232. #ds=db.selectRows(setup['project'],setup['schema'],setup['query'],[refFilter],setup['view'])
  233. #parFileString=ds['rows'][0]['parameterFileString']
  234. #parFiles=parFileString.split(';')
  235. remoteDir=fb.formatPathURL(setup['project'],'/'.join(['jobs',ref]))
  236. try:
  237. localDir=setup['localDir']
  238. except KeyError:
  239. localDir=os.path.join(os.path.expanduser('~'),'temp','jobDir')
  240. if not os.path.isdir(localDir):
  241. os.mkdir(localDir)
  242. #download setup
  243. f='setup.json'
  244. localPath=os.path.join(localDir,f)
  245. remotePath='/'.join([remoteDir,f])
  246. fb.readFileToFile(remotePath,localPath)
  247. setupFile=os.path.join(localDir,f)
  248. setupOld=parseSetup(setupFile)
  249. inFiles=getFiles(setupOld,loadAll)
  250. #inFiles.extend(parFiles)
  251. i=0
  252. n=len(inFiles)
  253. for fSet in inFiles:
  254. for x in fSet:
  255. f=fSet[x]
  256. localPath=os.path.join(localDir,f)
  257. remotePath='/'.join([remoteDir,f])
  258. fb.readFileToFile(remotePath,localPath)
  259. print('Loaded {}/{} {}'.format(i+1,n,localDir))
  260. i+=1
  261. return loadSolutionFromDir(localDir,loadAll)
  262. def merge(a1,a2):
  263. try:
  264. return numpy.concatenate(a1,a2)
  265. except ValueError:
  266. return a2
  267. def loadSolutionFromDir(jobDir,loadAll=False):
  268. setupFile=os.path.join(jobDir,'setup.json')
  269. setup=parseSetup(setupFile)
  270. inFiles=getFiles(setup,loadAll)
  271. isFirst=True
  272. operators={x:numpy.loadtxt for x in inFiles[0]}
  273. operators['sOut']=read3D
  274. data={}
  275. i=0
  276. n=len(inFiles)
  277. for fSet in inFiles:
  278. idata={}
  279. print('Parsing [{}/{}]'.format(i+1,n))
  280. for f in fSet:
  281. path=os.path.join(jobDir,fSet[f])
  282. idata=operators[f](os.path.join(jobDir,fSet[f]))
  283. if f=='sOut':
  284. lut=idata[1]
  285. lutSE=idata[2]
  286. idata=idata[0]
  287. try:
  288. data[f]=numpy.concatenate((data[f],idata))
  289. except KeyError:
  290. data[f]=idata
  291. i+=1
  292. return data['t'],data['sol'],data['se'],data['sOut'],data['qt'],lut,lutSE,setup
  293. def getStartPointFromDir(jobDir):
  294. t,sol,se,sOut,qt,lut,lutSE,setup=loadSolutionFromDir(jobDir)
  295. return t[-1],sol[-1],sOut[-1],lut,lutSE
  296. def getStartPoint(setup):
  297. if setup['startFromRef']=='None':
  298. return 0,numpy.array([]),numpy.array([]),[],[]
  299. t,sol,se,sOut,qt,lut,lutSE,oldSetup=loadSolutionFromRef(setup)
  300. return t[-1],sol[-1],sOut[-1],lut,lutSE
  301. if __name__=="__main__":
  302. parFiles=sys.argv[1].split(';')
  303. jobDir=sys.argv[2]
  304. main(parFiles,jobDir)