ttb_change.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. """
  2. TTB change - test if a change to a code provides exactly the same results
  3. Provide a list with runid's for all runs to be compared:
  4. o the first is the id for the reference run,
  5. output of other runs is compared to this one;
  6. o proper settings for each run should be set in
  7. the template rcfile using '#if' keywords etc:
  8. ttb.change.runids : ref test
  9. If it is not necessary to run some of these, for example
  10. because their code did not change, include their id's in
  11. a second list; for example, to skip the "ref" run:
  12. ttb.change.runids.no-run : ref
  13. To define what of the output should be compared,
  14. provide a list with one or more keywords:
  15. 'restart' : restart files (best choice!)
  16. 'save' : save files
  17. 'save-cy1' : save files in cy1 format
  18. 'budget_global' : global budget file
  19. 'budget_global-cy1' : global budget file in cy1 format (dataset for each region)
  20. For example, to just compare the restart files:
  21. ttb.change.compare : restart
  22. """
  23. # ***
  24. def MyLogger( name ) :
  25. # external:
  26. import logging
  27. import sys
  28. # setup logger:
  29. logger = logging.getLogger( name )
  30. # no handlers yet ? then print to standard output:
  31. if len(logger.handlers) == 0 : logger.addHandler(logging.StreamHandler(sys.stdout))
  32. # no level set yet ? then set for info and higher:
  33. if logger.level == 0 : logger.setLevel(logging.INFO)
  34. # ok:
  35. return logger
  36. #enddef
  37. # ***
  38. def Test( rcf, build_jobs=None, build_new=False ) :
  39. # external:
  40. import sys
  41. import os
  42. import datetime
  43. import subprocess
  44. import traceback
  45. # tools:
  46. import rc
  47. import ttb_compare
  48. # get logger:
  49. logger = MyLogger('ttb')
  50. # test name:
  51. test_name = 'change'
  52. # info ...
  53. logger.info( ' "%s" test ...' % test_name )
  54. # name of TM5 rcfile:
  55. tm_rcfile = rcf.get( 'ttb.rcfile' )
  56. # load the tm5 rcfile:
  57. tm_rcf = rc.RcFile( tm_rcfile )
  58. # flags:
  59. no_run = rcf.get( 'ttb.no-run', 'bool' )
  60. # run id's:
  61. runids = rcf.get( 'ttb.%s.runids' % test_name ).split()
  62. # do not run some of them:
  63. runids_no_run = rcf.get( 'ttb.%s.runids.no-run' % test_name ).split()
  64. # keywords for what to compare: save, restart, ...
  65. to_compares = rcf.get( 'ttb.%s.compare' % test_name ).split()
  66. # is failue an error ? otherwise messages are displayed and testing is continued:
  67. error_on_failure = rcf.get( 'ttb.%s.error_on_failure' % test_name, 'bool' )
  68. # init lists:
  69. test_rcfs = {}
  70. # loop over runs:
  71. for irun in range(len(runids)) :
  72. # current value:
  73. runid = runids[irun]
  74. #
  75. # run model
  76. #
  77. # read template rcfile in raw format:
  78. test_rcf_raw = rc.RcFile( tm_rcfile, raw=True )
  79. # replace runid:
  80. test_rcf_raw.replace( 'runid', runid )
  81. # target filename: tmp-<origingal_basename>-<runid>.rc
  82. bname,ext = os.path.splitext(tm_rcfile)
  83. test_rcfile_test = 'tmp-ttb-%s-%s.rc' % (test_name,runid)
  84. # write:
  85. test_rcf_raw.WriteFile( test_rcfile_test )
  86. # read again:
  87. test_rcf = rc.RcFile( test_rcfile_test )
  88. # store name:
  89. test_rcfs[runid] = test_rcf
  90. # run if necessary:
  91. if (not no_run) and (runid not in runids_no_run) :
  92. logger.info( '' )
  93. logger.info( '******************************************************************' )
  94. logger.info( '' )
  95. logger.info( '%s' % runid )
  96. logger.info( '' )
  97. logger.info( '******************************************************************' )
  98. logger.info( '' )
  99. # setup and submit command:
  100. command = [os.path.join(os.curdir,'setup_tm5'), test_rcfile_test, '--submit']
  101. if build_new : command = command + ['--new']
  102. if build_jobs != None : command = command + ['--jobs',build_jobs]
  103. retcode = subprocess.call( command )
  104. if retcode != 0 :
  105. logger.error( 'from call:' )
  106. logger.error( ' %s' % command )
  107. raise Exception
  108. #endif
  109. #endif # run model
  110. #
  111. # check results
  112. #
  113. # can be compared to reference ?
  114. if irun > 0 :
  115. # runid of reference is the first:
  116. runid_ref = runids[0]
  117. # flag ...
  118. found_diffs = False
  119. # loop over comparisions:
  120. for to_compare in to_compares :
  121. # select:
  122. if to_compare == 'restart' :
  123. # which regions ?
  124. regions = test_rcf.get( 'regions' ).split()
  125. # end time:
  126. tfmt = '%Y-%m-%d %H:%M:%S'
  127. t = datetime.datetime.strptime( tm_rcf.get('timerange.end'), tfmt )
  128. # info ...
  129. logger.info( '' )
  130. logger.info( 'compare output files ...' )
  131. # loop over regions
  132. for region in regions :
  133. # files to be compared:
  134. fnames = []
  135. for runid2 in [runid_ref,runid] :
  136. # directory with restart files:
  137. fdir = test_rcfs[runid2].get('restart.store.dir')
  138. # target file:
  139. fnam = 'TM5_restart_%s_%s.nc' % (t.strftime('%Y%m%d_%H%M'),region)
  140. # add:
  141. fnames.append( os.path.join(fdir,fnam) )
  142. #endfor
  143. # compare ...
  144. try :
  145. ttb_compare.df_files( fnames[0], fnames[1] )
  146. except ValueError :
  147. found_diffs = True
  148. except :
  149. for line in traceback.format_exc().split('\n') : logger.error(line)
  150. raise Exception
  151. #endtry
  152. #endfor # regions
  153. elif to_compare == 'save-cy1' :
  154. # which regions ?
  155. regions = test_rcf.get( 'regions' ).split()
  156. # info ...
  157. logger.info( '' )
  158. logger.info( 'compare save files ...' )
  159. # loop over regions
  160. for region in regions :
  161. # files to be compared:
  162. fnames = []
  163. for runid2 in [runid_ref,runid] :
  164. # target file:
  165. fnam = 'save_%s.hdf' % region
  166. # directory with save files:
  167. output_dir = test_rcfs[runid2].get( 'output.dir' )
  168. subdir = test_rcf.get( 'save.output.subdir', default='' )
  169. fdir = os.path.join( output_dir, subdir )
  170. # add full path:
  171. fnames.append( os.path.join(fdir,fnam) )
  172. #endfor
  173. # compare ...
  174. try :
  175. ttb_compare.df_files( fnames[0], fnames[1] )
  176. except ValueError :
  177. found_diffs = True
  178. except :
  179. for line in traceback.format_exc().split('\n') : logger.error(line)
  180. raise Exception
  181. #endtry
  182. #endfor # regions
  183. elif to_compare in ['save'] :
  184. # which regions ?
  185. regions = test_rcf.get( 'regions' ).split()
  186. # end time:
  187. tfmt = '%Y-%m-%d %H:%M:%S'
  188. t = datetime.datetime.strptime( tm_rcf.get('timerange.end' ), tfmt )
  189. # info ...
  190. logger.info( '' )
  191. logger.info( 'compare %s files ...' % to_compare )
  192. # loop over regions
  193. for region in regions :
  194. # files to be compared:
  195. fnames = []
  196. for runid2 in [runid_ref,runid] :
  197. # target file:
  198. fnam = '%s_%s_%s.hdf' % (to_compare,t.strftime('%Y%m%d%H%M'),region)
  199. # directory with save files:
  200. output_dir = test_rcfs[runid2].get( 'output.dir' )
  201. subdir = test_rcf.get( 'save.output.subdir', default='' )
  202. fdir = os.path.join( output_dir, subdir )
  203. # add full path:
  204. fnames.append( os.path.join(fdir,fnam) )
  205. #endfor
  206. # compare ...
  207. try :
  208. ttb_compare.df_files( fnames[0], fnames[1] )
  209. except ValueError :
  210. found_diffs = True
  211. except :
  212. for line in traceback.format_exc().split('\n') : logger.error(line)
  213. raise Exception
  214. #endtry
  215. #endfor # regions
  216. elif to_compare in ['adj_save'] :
  217. # which regions ?
  218. regions = test_rcf.get( 'regions' ).split()
  219. # end time:
  220. tfmt = '%Y-%m-%d %H:%M:%S'
  221. t = datetime.datetime.strptime( tm_rcf.get('timerange.start' ), tfmt )
  222. # info ...
  223. logger.info( '' )
  224. logger.info( 'compare %s files ...' % to_compare )
  225. # loop over regions
  226. for region in regions :
  227. # files to be compared:
  228. fnames = []
  229. for runid2 in [runid_ref,runid] :
  230. # target file:
  231. fnam = '%s_%s_%s.hdf' % (to_compare,t.strftime('%Y%m%d%H%M'),region)
  232. # directory with save files:
  233. output_dir = test_rcfs[runid2].get( 'output.dir' )
  234. subdir = test_rcf.get( 'save.output.subdir', default='' )
  235. fdir = os.path.join( output_dir, subdir )
  236. # add full path:
  237. fnames.append( os.path.join(fdir,fnam) )
  238. #endfor
  239. # compare ...
  240. try :
  241. ttb_compare.df_files( fnames[0], fnames[1] )
  242. except ValueError :
  243. found_diffs = True
  244. except :
  245. for line in traceback.format_exc().split('\n') : logger.error(line)
  246. raise Exception
  247. #endtry
  248. #endfor # regions
  249. elif to_compare == 'budget_global-cy1' :
  250. # info ...
  251. logger.info( '' )
  252. logger.info( 'compare budget_global files ...' )
  253. # files to be compared:
  254. fnames = []
  255. for runid2 in [runid_ref,runid] :
  256. # target file:
  257. fnam = 'budget_global.hdf'
  258. # directory with save files:
  259. output_dir = test_rcfs[runid2].get( 'output.dir' )
  260. subdir = test_rcf.get( 'budget.output.subdir', default='' )
  261. fdir = os.path.join( output_dir, subdir )
  262. # add full path:
  263. fnames.append( os.path.join(fdir,fnam) )
  264. #endfor
  265. # budget_global.hdf files contain datasets with the same name
  266. # for different regions:
  267. for iregion in range(len(regions)) :
  268. # compare ...
  269. try :
  270. ttb_compare.df_files( fnames[0], fnames[1], sample=iregion+1 )
  271. except ValueError :
  272. found_diffs = True
  273. except :
  274. for line in traceback.format_exc().split('\n') : logger.error(line)
  275. raise Exception
  276. #endtry
  277. #endfor
  278. elif to_compare == 'budget_global' :
  279. # info ...
  280. logger.info( '' )
  281. logger.info( 'compare budget_global files ...' )
  282. # files to be compared:
  283. fnames = []
  284. for runid2 in [runid_ref,runid] :
  285. # target file:
  286. fnam = 'budget_global.hdf'
  287. # directory with save files:
  288. output_dir = test_rcfs[runid2].get( 'output.dir' )
  289. subdir = test_rcf.get( 'budget.output.subdir', default='' )
  290. fdir = os.path.join( output_dir, subdir )
  291. # add full path:
  292. fnames.append( os.path.join(fdir,fnam) )
  293. #endfor
  294. # compare ...
  295. try :
  296. ttb_compare.df_files( fnames[0], fnames[1] )
  297. except ValueError :
  298. found_diffs = True
  299. except :
  300. for line in traceback.format_exc().split('\n') : logger.error(line)
  301. raise Exception
  302. #endtry
  303. else :
  304. logger.error( 'unsupported comparision : %s' % to_compare )
  305. raise ValueError
  306. #endif
  307. #endfor # comparisons
  308. # any differences ?
  309. if found_diffs and error_on_failure :
  310. logger.error( 'found some differences; quit' )
  311. return
  312. #endif
  313. #endif $ irun > 0
  314. #
  315. # *
  316. #
  317. #endfor # runids
  318. #enddef