uploadIncompleteRun.py 10 KB

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