pycasso_user_scripts_tm5.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. """
  2. PYCASSO User Scripts
  3. Do not change the arguments of the defined routines, only their content !
  4. """
  5. #-------------------------------------------------
  6. # arguments and options
  7. #-------------------------------------------------
  8. def DefineOptions( parser ) :
  9. """
  10. Usage : DefineOptions( parser )
  11. Define options supported by user scripts.
  12. Arugments:
  13. parser : optparse object
  14. """
  15. # define flag to clean source code:
  16. parser.add_option( "-c", "--clean",
  17. help="Remove high level object and module files before "
  18. "compilation. Low level objects from for example the "
  19. "'file_hdf' sources are not removed to speedup "
  20. "re-compilation of the model. "
  21. "To have all objects removed, use the '--new' option "
  22. "to create a complete new build; in older scripts "
  23. "an option '-C' or '--clean-all' was defined for this.",
  24. dest="clean", action="store_true", default=False )
  25. parser.add_option( "--steps", help="'stages list' (can contains: init, run, done, all) that overwrites job.steps from expert rc file.",
  26. dest="stages")
  27. # Useful options for coupling TM5 to EC-Earth
  28. parser.add_option("--time-start", help="'yyyy-mm-dd hh:mn:ss' that overwrites timerange.start of rc file.",
  29. dest="time_start")
  30. parser.add_option("--time-final", help="'yyyy-mm-dd hh:mn:ss' that overwrites timerange.end of rc file.",
  31. dest="time_end")
  32. parser.add_option("--istart", help="overwrite istart of rc file. No effect if empty string ''", dest="istart")
  33. return
  34. # *
  35. def StoreOptions( settings, values ) :
  36. """
  37. Add the parsed flags ('values') to the 'settings' dictionary.
  38. The values have data fields with names defined by 'dest'
  39. in the previous calls to 'parser.add_option' .
  40. """
  41. # translate options into a dictionairy if they should
  42. # replace rcfile values:
  43. if values.clean : settings['build.make.clean'] = True
  44. if values.stages != None : settings['job.steps'] = values.stages
  45. # Useful for EC-Earth
  46. if values.time_start != None : settings['timerange.start'] = values.time_start
  47. if values.time_end != None : settings['timerange.end' ] = values.time_end
  48. if values.time_start != None : settings['jobstep.timerange.start'] = values.time_start
  49. if values.time_end != None : settings['jobstep.timerange.end' ] = values.time_end
  50. if values.istart != None :
  51. if len(values.istart): settings['istart'] = values.istart
  52. return
  53. #-------------------------------------------------
  54. # source
  55. #-------------------------------------------------
  56. def Build_FlagGroups( rcf, basic=False ) :
  57. """
  58. Return list of compiler flag groups to be used.
  59. """
  60. # default :
  61. flaggroups = ['default','real8']
  62. # add mpi ?
  63. if rcf.get('par.mpi','bool') : flaggroups.append('mpi')
  64. # Get full list of TM flags
  65. line = rcf.get('build.configure.flags').split()
  66. # Add 'debug' and 'check-all' to basics group
  67. if 'check-all' in line:
  68. flaggroups += ['check-all']
  69. line.remove('check-all')
  70. if 'debug' in line:
  71. flaggroups += ['debug']
  72. line.remove('debug')
  73. # include not standard flags ?
  74. if not basic :
  75. # add openmp ?
  76. if rcf.get('par.openmp','bool') : flaggroups.append('openmp')
  77. flaggroups += line
  78. ## add adjoint ?
  79. #if rcf.get('var4d','bool') : flaggroups.append('adj')
  80. return flaggroups
  81. # ***
  82. def Build_Define( rcf, macro_group, mdefs ) :
  83. """
  84. Edit a list with macro's to be defined given
  85. the name of group of macro's and the other setings
  86. in the rcfile.
  87. """
  88. # external:
  89. import logging
  90. # info ...
  91. logging.info( ' user script Build_Define for macro group %s ...' % macro_group )
  92. # select on macro group name:
  93. if macro_group == 'tm5' :
  94. # macro to include checks on zooming;
  95. # required for zoom runs, but should be undefined
  96. # for runs without zooming to speedup the program:
  97. mac = 'with_zoom'
  98. # regions defined via a list in the rcfile ?
  99. if len(rcf.get('regions',default='')) > 0 :
  100. # number of regions:
  101. nregions = len(rcf.get('regions').split())
  102. else :
  103. # the 'old' method defines the grid via source files;
  104. # key 'source.nregions' from the rcfile is used to set the actual number:
  105. nregions_text = rcf.get('source.nregions')
  106. # check for special value:
  107. if nregions_text == 'nregions_max' :
  108. nregions = 999
  109. else :
  110. nregions = int(nregions_text)
  111. #endif
  112. #endif
  113. # zoom regions ? then
  114. if nregions > 1 :
  115. # define macro 'with_zoom' if not present yet:
  116. if mac not in mdefs :
  117. # add:
  118. mdefs.append( mac )
  119. # info ...
  120. logging.info( ' defined %s ...' % mac )
  121. #endif
  122. else :
  123. # no zooming, remove macro 'with_zoom' if present:
  124. if mac in mdefs :
  125. # remove:
  126. mdefs.remove( mac )
  127. # info ...
  128. logging.info( ' undefined %s ...' % mac )
  129. #endif
  130. #endif
  131. # macro's to enable MPI specific code:
  132. macs = ['MPI']
  133. # loop:
  134. for mac in macs :
  135. # MPI enabled ?
  136. if rcf.get('par.mpi','bool') :
  137. # define macro 'with_zoom' if not present yet:
  138. if mac not in mdefs :
  139. # add:
  140. mdefs.append( mac )
  141. # info ...
  142. logging.info( ' defined %s ...' % mac )
  143. else :
  144. # MPI not enabled, remove if necessary:
  145. if mac in mdefs :
  146. # add:
  147. mdefs.remove( mac )
  148. # info ...
  149. logging.info( ' undefined %s ...' % mac )
  150. return mdefs
  151. # ***
  152. def Build_Configure( rcf ) :
  153. """
  154. Configure a source code.
  155. This script is called from the source directory.
  156. Arguments:
  157. rcf : dictionairy with settings from rc file
  158. """
  159. # external
  160. import logging
  161. # info ...
  162. logging.info( ' user script Build_Configure ...' )
  163. # write grid definitions:
  164. Build_Configure_Grid( rcf )
  165. # check on depricated stuff ...
  166. Build_Configure_Check( rcf )
  167. return
  168. # *
  169. def Build_Configure_Grid( rcf ) :
  170. """
  171. Write source files for grid definition.
  172. """
  173. # external:
  174. import logging
  175. # info ...
  176. logging.info( ' user script Build_Configure_Grid ...' )
  177. # regions are defined either by a list of region names ('regions') ,
  178. # or the older method using 'source.nregions' and 'dims_grid.h' :
  179. if len(rcf.get('regions',default='')) > 0 :
  180. # write all source files:
  181. Build_Configure_Grid__regions( rcf )
  182. elif rcf.has_key('source.nregions') :
  183. # write only number of regions to include file:
  184. Build_Configure_Grid__nregions( rcf )
  185. else :
  186. logging.error( 'could not extract number of regions from rcfile settings;' )
  187. logging.error( 'either "regions" or "source.nregions" should be defined' )
  188. raise Exception
  189. return
  190. # *
  191. def Build_Configure_Grid__nregions( rcf ) :
  192. """
  193. Write 'dims_grid.h' from rcfile settings.
  194. """
  195. # external:
  196. import logging
  197. import pycasso_tools
  198. # info ...
  199. logging.info( ' user script Build_Configure_Grid__nregions ...' )
  200. # which file to create ?
  201. srcfile = 'dims_grid.h'
  202. # info ...
  203. logging.info( ' create %s ...' % srcfile )
  204. # number of regions; could be the name 'nregions_max', thus read as string:
  205. source_nregions = rcf.get('source.nregions')
  206. # fill lines:
  207. lines = []
  208. lines.append( '!\n' )
  209. lines.append( '! Define actual number of regions.\n' )
  210. lines.append( '! Included by \'dims_grid.F90\'.\n' )
  211. lines.append( '!\n' )
  212. lines.append( 'integer, parameter :: nregions = %s\n' % source_nregions )
  213. # update file if necessary ...
  214. pycasso_tools.update_text_file( srcfile, lines )
  215. return
  216. # *
  217. def Build_Configure_Grid__regions( rcf ) :
  218. """
  219. Write 'dims_grid.F90' from rcfile settings.
  220. """
  221. # external:
  222. import logging
  223. import pycasso_tools
  224. # info ...
  225. logging.info( ' user script Build_Configure_Grid__regions ...' )
  226. # which file to create ?
  227. srcfile = 'dims_grid.F90'
  228. # different versions could be made, depending on the release (former cycle);
  229. # get the target release, use ininite number ('latest' release) as default:
  230. build_release = rcf.get( 'build.configure.release', 'float', default=999.9 )
  231. # info ...
  232. logging.info( ' create %s ...' % srcfile )
  233. # model regions:
  234. regions = rcf.get('regions').split()
  235. # old or new style ...
  236. if build_release < 3.0 :
  237. # actual number:
  238. nregions = len(regions)
  239. # maximum length of grid names:
  240. len_region_name = max(map(len,regions))
  241. # other ...
  242. maxref = rcf.get('region.maxref')
  243. dx = rcf.get('region.dx')
  244. dy = rcf.get('region.dy')
  245. dz = rcf.get('region.dz')
  246. # start with empty file:
  247. lines = []
  248. lines.append( '!#################################################################\n' )
  249. lines.append( '!\n' )
  250. lines.append( '! Grids.\n' )
  251. lines.append( '!\n' )
  252. lines.append( '!### macro\'s #####################################################\n' )
  253. lines.append( '!\n' )
  254. lines.append( '#include "tm5.inc"\n' )
  255. lines.append( '!\n' )
  256. lines.append( '!#################################################################\n' )
  257. lines.append( '\n' )
  258. lines.append( 'module dims_grid\n' )
  259. lines.append( '\n' )
  260. lines.append( ' implicit none\n' )
  261. lines.append( ' \n' )
  262. lines.append( ' ! --- in/out ------------------------------\n' )
  263. lines.append( ' \n' )
  264. lines.append( ' public\n' )
  265. lines.append( ' \n' )
  266. lines.append( ' \n' )
  267. lines.append( ' ! --- const -------------------------------\n' )
  268. lines.append( ' \n' )
  269. lines.append( ' \n' )
  270. lines.append( ' ! Basic model definition: resolution etc. including some routines\n' )
  271. lines.append( ' ! to fill the data structure.\n' )
  272. lines.append( '\n' )
  273. lines.append( ' ! basic (coarsest) resolution in degrees for x and y (dz default 1.0)\n' )
  274. lines.append( '\n' )
  275. lines.append( ' real, parameter :: dx = %s\n' % dx )
  276. lines.append( ' real, parameter :: dy = %s\n' % dy )
  277. lines.append( ' real, parameter :: dz = %s\n' % dz )
  278. lines.append( '\n' )
  279. lines.append( '\n' )
  280. lines.append( ' ! Maximum number of zoom regions, \n' )
  281. lines.append( ' ! including the basic (coarsest grid) region;\n' )
  282. lines.append( ' ! arrays are allocated for each of these regions:\n' )
  283. lines.append( ' integer, parameter :: nregions_max = %i\n' % nregions )
  284. lines.append( ' \n' )
  285. lines.append( ' ! Actual number of zoom regions,\n' )
  286. lines.append( ' ! during testing this could be set to 1 to quickly run the model.\n' )
  287. lines.append( ' integer, parameter :: nregions = %s\n' % nregions )
  288. lines.append( '\n' )
  289. lines.append( ' ! region_name is used to recognise the METEO files\n' )
  290. lines.append( ' ! region_name is also used in the HDF output file name\n' )
  291. lines.append( ' ! region 1 should always be the global domain\n' )
  292. lines.append( '\n' )
  293. lines.append( ' integer, parameter :: len_region_name = %i\n' % len_region_name )
  294. lines.append( ' character(len=len_region_name), parameter :: region_name(1:nregions) = &\n' )
  295. line = ' (/ '
  296. for i in range(len(regions)) :
  297. if i > 0 : line = line + ', '
  298. fmt = "'%%-%is'" % len_region_name
  299. line = line + ( fmt % regions[i] )
  300. #endfor
  301. lines.append( line+'/)\n' )
  302. lines.append( '\n' )
  303. lines.append( ' ! coordinates (in degrees) for each region:\n' )
  304. lines.append( ' ! xcyc = 1 if the region has cyclic x-boundary conditions\n' )
  305. lines.append( ' ! touch_np = 1 if region touches the north pole\n' )
  306. lines.append( ' ! touch_sp = 1 if region touches the south pole\n' )
  307. lines.append( ' ! xbeg : the westmost border of the region\n' )
  308. lines.append( ' ! xend : the eastmost border of the region\n' )
  309. lines.append( ' ! ybeg : the southmost border of the region\n' )
  310. lines.append( ' ! yend : the northmost border of the region\n' )
  311. lines.append( '\n' )
  312. fields = ['xcyc','touch_np','touch_sp','xbeg','xend','ybeg','yend','im','jm']
  313. for ifield in range(len(fields)) :
  314. field = fields[ifield]
  315. line = ' integer, parameter :: %-8s(nregions) = (/ ' % field
  316. for iregion in range(len(regions)) :
  317. region = regions[iregion]
  318. if iregion > 0 : line = line + ', '
  319. val = rcf.get( 'region.%s.%s' % (region,field) )
  320. line = line + ( '%4i' % int(val) )
  321. #endfor
  322. lines.append( line+' /)\n' )
  323. #endfor
  324. lines.append( '\n' )
  325. lines.append( '\n' )
  326. lines.append( ' ! maximum refinement factor (can be arbitrary in principle):\n' )
  327. lines.append( '\n' )
  328. lines.append( ' integer, parameter :: maxref = %s\n' % maxref )
  329. lines.append( '\n' )
  330. lines.append( ' ! refinement factors for each region (<= maxref)\n' )
  331. lines.append( ' ! tref may differ from xref/yref. In the current \n' )
  332. lines.append( ' ! implementation it should be 1,2,4,6,...\n' )
  333. lines.append( '\n' )
  334. fields = ['xref','yref','zref','tref']
  335. for ifield in range(len(fields)) :
  336. field = fields[ifield]
  337. line = ' integer, parameter :: %s(0:nregions) = (/ 1' % field
  338. for i in range(nregions) :
  339. #if i > 0 : line = line + ', '
  340. line = line + ', '
  341. val = rcf.get( 'region.%s.%s' % (regions[i],field) )
  342. line = line + ( '%4i' % int(val) )
  343. #endfor
  344. lines.append( line+' /)\n' )
  345. #endfor
  346. lines.append( '\n' )
  347. lines.append( ' ! Define the parent of each region. \n' )
  348. lines.append( ' ! Global region 1 should have parent 0 (globe single cell);\n' )
  349. lines.append( ' ! global surface region should have parent 1 (global region).\n' )
  350. line = ' integer, parameter :: parent(nregions) = (/ '
  351. for i in range(nregions) :
  352. if i > 0 : line = line + ', '
  353. val = rcf.get( 'region.%s.parent' % regions[i] )
  354. if val == 'globe' :
  355. ireg = 0
  356. else :
  357. ireg = regions.index(val) + 1
  358. #endif
  359. line = line + ( '%i' % ireg )
  360. #endfor
  361. lines.append( line+' /)\n' )
  362. lines.append( '\n' )
  363. lines.append( 'end module dims_grid\n' )
  364. else : # release 3.0 and higher
  365. # maximum number of 'zooming' model regions:
  366. nregions_max = len(regions)
  367. # add global surface grid if necessary:
  368. region_glbsfc = rcf.get('region.glbsfc')
  369. if len(region_glbsfc) > 0 : regions = regions + [region_glbsfc]
  370. # all regions:
  371. nregions_all = len(regions)
  372. # start with global grid:
  373. regions = [rcf.get('region.globe')] + regions
  374. # actual number is the maximum ...
  375. nregions = 'nregions_max'
  376. # maximum length of grid names:
  377. len_region_name = max(map(len,regions))
  378. # other ...
  379. maxref = rcf.get('region.maxref')
  380. dx = rcf.get('region.dx')
  381. dy = rcf.get('region.dy')
  382. dz = rcf.get('region.dz')
  383. # fill lines:
  384. lines = []
  385. lines.append( '!#################################################################\n' )
  386. lines.append( '!\n' )
  387. lines.append( '! Grids.\n' )
  388. lines.append( '!\n' )
  389. lines.append( '!### macro\'s #####################################################\n' )
  390. lines.append( '!\n' )
  391. lines.append( '#include "tm5.inc"\n' )
  392. lines.append( '!\n' )
  393. lines.append( '!#################################################################\n' )
  394. lines.append( '\n' )
  395. lines.append( 'module dims_grid\n' )
  396. lines.append( '\n' )
  397. lines.append( ' implicit none\n' )
  398. lines.append( ' \n' )
  399. lines.append( ' ! --- in/out ------------------------------\n' )
  400. lines.append( ' \n' )
  401. lines.append( ' public\n' )
  402. lines.append( ' \n' )
  403. lines.append( ' \n' )
  404. lines.append( ' ! --- const -------------------------------\n' )
  405. lines.append( ' \n' )
  406. lines.append( ' \n' )
  407. lines.append( ' ! Basic model definition: resolution etc. including some routines\n' )
  408. lines.append( ' ! to fill the data structure.\n' )
  409. lines.append( '\n' )
  410. lines.append( ' ! basic (coarsest) resolution in degrees for x and y (dz default 1.0)\n' )
  411. lines.append( '\n' )
  412. lines.append( ' real, parameter :: dx = %s\n' % dx )
  413. lines.append( ' real, parameter :: dy = %s\n' % dy )
  414. lines.append( ' real, parameter :: dz = %s\n' % dz )
  415. lines.append( '\n' )
  416. lines.append( '\n' )
  417. lines.append( ' ! Maximum number of zoom regions, \n' )
  418. lines.append( ' ! including the basic (coarsest grid) region;\n' )
  419. lines.append( ' ! arrays are allocated for each of these regions:\n' )
  420. lines.append( ' integer, parameter :: nregions_max = %i\n' % nregions_max )
  421. lines.append( ' \n' )
  422. if len(region_glbsfc) > 0 :
  423. lines.append( ' ! extra grid:\n' )
  424. lines.append( ' integer, parameter :: nregions_all = nregions_max + 1\n' )
  425. lines.append( ' integer, parameter :: iglbsfc = nregions_max + 1\n' )
  426. else :
  427. lines.append( ' ! no extra surface grid, use the global model grid for this:\n' )
  428. lines.append( ' integer, parameter :: nregions_all = nregions_max\n' )
  429. lines.append( ' integer, parameter :: iglbsfc = 1\n' )
  430. lines.append( '\n' )
  431. lines.append( ' ! Actual number of zoom regions,\n' )
  432. lines.append( ' ! during testing this could be set to 1 to quickly run the model.\n' )
  433. lines.append( ' integer, parameter :: nregions = %s\n' % nregions )
  434. lines.append( '\n' )
  435. lines.append( ' ! region_name is used to recognise the METEO files\n' )
  436. lines.append( ' ! region_name is also used in the HDF output file name\n' )
  437. lines.append( ' ! region 1 should always be the global domain\n' )
  438. lines.append( '\n' )
  439. lines.append( ' integer, parameter :: len_region_name = %i\n' % len_region_name )
  440. lines.append( ' character(len=len_region_name), parameter :: region_name(0:nregions_all) = &\n' )
  441. line = ' (/ '
  442. for i in range(len(regions)) :
  443. if i > 0 : line = line + ', '
  444. fmt = "'%%-%is'" % len_region_name
  445. line = line + ( fmt % regions[i] )
  446. lines.append( line+'/)\n' )
  447. lines.append( '\n' )
  448. lines.append( ' ! coordinates (in degrees) for each region:\n' )
  449. lines.append( ' ! xcyc = 1 if the region has cyclic x-boundary conditions\n' )
  450. lines.append( ' ! touch_np = 1 if region touches the north pole\n' )
  451. lines.append( ' ! touch_sp = 1 if region touches the south pole\n' )
  452. lines.append( ' ! xbeg : the westmost border of the region\n' )
  453. lines.append( ' ! xend : the eastmost border of the region\n' )
  454. lines.append( ' ! ybeg : the southmost border of the region\n' )
  455. lines.append( ' ! yend : the northmost border of the region\n' )
  456. lines.append( '\n' )
  457. fields = ['xcyc','touch_np','touch_sp','xbeg','xend','ybeg','yend','im','jm']
  458. for ifield in range(len(fields)) :
  459. field = fields[ifield]
  460. line = ' integer, parameter :: %-8s(0:nregions_all) = (/ ' % field
  461. for iregion in range(len(regions)) :
  462. region = regions[iregion]
  463. if iregion > 0 : line = line + ', '
  464. val = rcf.get( 'region.%s.%s' % (region,field) )
  465. line = line + ( '%4i' % int(val) )
  466. lines.append( line+' /)\n' )
  467. lines.append( '\n' )
  468. lines.append( '\n' )
  469. lines.append( ' ! maximum refinement factor (can be arbitrary in principle):\n' )
  470. lines.append( '\n' )
  471. lines.append( ' integer, parameter :: maxref = %s\n' % maxref )
  472. lines.append( '\n' )
  473. lines.append( ' ! refinement factors for each region (<= maxref)\n' )
  474. lines.append( ' ! tref may differ from xref/yref. In the current \n' )
  475. lines.append( ' ! implementation it should be 1,2,4,6,...\n' )
  476. lines.append( '\n' )
  477. fields = ['xref','yref','zref','tref']
  478. for ifield in range(len(fields)) :
  479. field = fields[ifield]
  480. line = ' integer, parameter :: %s(0:nregions_max) = (/ ' % field
  481. for i in range(0,nregions_max+1) :
  482. if i > 0 : line = line + ', '
  483. val = rcf.get( 'region.%s.%s' % (regions[i],field) )
  484. line = line + ( '%4i' % int(val) )
  485. lines.append( line+' /)\n' )
  486. lines.append( '\n' )
  487. lines.append( ' ! Define the parent of each region. \n' )
  488. lines.append( ' ! Global region 1 should have parent 0 (globe single cell);\n' )
  489. lines.append( ' ! global surface region should have parent 1 (global region).\n' )
  490. line = ' integer, parameter :: parent(1:nregions_all) = (/ '
  491. for i in range(1,nregions_all+1) :
  492. if i > 1 : line = line + ', '
  493. val = rcf.get( 'region.%s.parent' % regions[i] )
  494. # check ...
  495. if val not in regions :
  496. logging.error( 'parent "%s" of region %i "%s" not in (extended) region list : %s' % (val,i,regions[i],regions) )
  497. raise ValueError
  498. ireg = regions.index(val)
  499. line = line + ( '%i' % ireg )
  500. lines.append( line+' /)\n' )
  501. lines.append( '\n' )
  502. lines.append( 'end module dims_grid\n' )
  503. # update file if necessary ...
  504. pycasso_tools.update_text_file( srcfile, lines )
  505. return
  506. # *
  507. def Build_Configure_Check( rcf ) :
  508. """
  509. Check source file for undesired features.
  510. """
  511. # external:
  512. import logging
  513. import os
  514. import fnmatch
  515. # info ...
  516. logging.info( ' user script Build_Configure_Check ...' )
  517. # keywords for checks to be performed:
  518. checknames = rcf.get( 'build.configure.checks', default='' )
  519. # empty ? then leave:
  520. if len(checknames) == 0 : return
  521. # error or just warnings ?
  522. with_error = rcf.get( 'build.configure.checks.error', 'bool', default=False )
  523. # set flag:
  524. any_warning = False
  525. # list files:
  526. srcfiles = os.listdir( os.curdir )
  527. srcfiles.sort()
  528. # loop over checks:
  529. for checkname in checknames.split() :
  530. # paterns:
  531. test_msg = rcf.get( 'build.configure.check.%s.msg' % checkname )
  532. test_files = rcf.get( 'build.configure.check.%s.files' % checkname ).split()
  533. test_skip = rcf.get( 'build.configure.check.%s.skip' % checkname ).split()
  534. test_line = rcf.get( 'build.configure.check.%s.test' % checkname )
  535. test_help = rcf.get( 'build.configure.check.%s.help' % checkname )
  536. # set flags:
  537. matching_files = False
  538. # loop over files:
  539. for srcfile in srcfiles :
  540. # match with patern ?
  541. match = False
  542. for pat in test_files :
  543. match = match or fnmatch.fnmatch(srcfile,pat)
  544. if match : break
  545. if not match : continue
  546. # ... except if the name matches other patterns:
  547. match = False
  548. for pat in test_skip :
  549. match = match or fnmatch.fnmatch(srcfile,pat)
  550. if match : break
  551. if match : continue
  552. # read file:
  553. f = open( srcfile )
  554. lines = f.readlines()
  555. f.close()
  556. # search for something that is there, or something that is not there ...
  557. if test_line.startswith('not') :
  558. # by default no match:
  559. match = False
  560. # loop over lines:
  561. for line in lines :
  562. # test on this line:
  563. match = match or (not eval( test_line ))
  564. # try next file after first match ...
  565. if match : break
  566. # check next file if the requested code was found:
  567. if match : continue
  568. # revert:
  569. match = not match
  570. else :
  571. # by default no match:
  572. match = False
  573. # loop over lines:
  574. for line in lines[0:20] :
  575. # test on this line:
  576. match = match or eval( test_line )
  577. # leave after first match ...
  578. if match : break
  579. # found something ?
  580. if match :
  581. # info ...
  582. if not matching_files : logging.warning( ' %s : [found]' % test_msg )
  583. logging.warning( ' %s' % srcfile )
  584. # reset flags:
  585. matching_files = True
  586. any_warning = True
  587. # info ...
  588. if matching_files :
  589. # display error message ?
  590. if with_error :
  591. # display help text; split at '\n' for newlines:
  592. for helpline in test_help.split('\\n') : logging.warning(helpline)
  593. else :
  594. # no warnings for this test ...
  595. logging.info( ' %s [none ]' % test_msg )
  596. # check for unknown macro's ?
  597. checkname = 'unknown_macro'
  598. flag = rcf.get( 'build.configure.check.%s' % checkname )
  599. if flag :
  600. # settings:
  601. test_msg = rcf.get( 'build.configure.check.%s.msg' % checkname )
  602. # names of macro groups:
  603. macgroups = rcf.get( 'build.configure.macro.groups' ).split()
  604. # collect all supported macro's:
  605. macall = []
  606. for macgroup in macgroups :
  607. macs = rcf.get( 'build.configure.macro.%s.all' % macgroup ).split()
  608. macall = macall + macs
  609. # flag ...
  610. logged_msg = False
  611. # loop over files:
  612. for srcfile in srcfiles :
  613. # read file (only if not *.mod, *.o or directory):
  614. if os.path.isdir(srcfile) : continue
  615. if fnmatch.fnmatch(srcfile,"*.mod") : continue
  616. if fnmatch.fnmatch(srcfile,"*.o") : continue
  617. f = open( srcfile )
  618. lines = f.readlines()
  619. f.close()
  620. # flags:
  621. logged_srcfile = False
  622. # loop over lines:
  623. for iline in range(len(lines)) :
  624. # current:
  625. line = lines[iline].strip()
  626. # macro test ?
  627. if line.startswith('#ifdef') or line.startswith('#ifndef') :
  628. # second element of line is macro name:
  629. mac = line.split()[1].strip()
  630. # not supported ?
  631. if mac not in macall :
  632. # test description if not done yet:
  633. if not logged_msg :
  634. logging.info( ' %s' % test_msg )
  635. logged_msg = True
  636. #endif
  637. # intro if necessary:
  638. if not logged_srcfile :
  639. logging.error( ' unsupported macro(s) in %s :' % srcfile )
  640. logged_srcfile = True
  641. #endif
  642. # line number and content:
  643. logging.error( ' %6i : %s' % (iline,line) )
  644. # set flag:
  645. any_warning = True
  646. # jippy ...
  647. if not logged_msg :
  648. # no warnings for this test ...
  649. logging.info( ' %s [none ]' % test_msg )
  650. # break ?
  651. if any_warning and with_error :
  652. logging.error( 'some source code checks failed; break' )
  653. logging.error( '(set "build.configure.checks.error : False" in the expert.rc to avoid this error)' )
  654. raise Exception
  655. return
  656. # ***
  657. def Build_Compiler( rcf ) :
  658. """
  659. Set compiler and linker names.
  660. Usually it is enough to read the name from the rcfile,
  661. but some compiler families have aliases for compilation with
  662. MPI or OpenMP enabled.
  663. Arguments:
  664. rcf : dictionary with settings from rc file
  665. Return values:
  666. fc,linker
  667. """
  668. # external
  669. import logging
  670. import go_subprocess
  671. # info ...
  672. logging.info( ' user script Build_Compiler ...' )
  673. # extract compiler name:
  674. fc = rcf.get('compiler.fc')
  675. # or supporting openmp ?
  676. if rcf.get('par.openmp','bool') : fc = rcf.get( 'compiler.fc.openmp' )
  677. # or with mpi support ?
  678. if rcf.get('par.mpi','bool') :
  679. # extract compiler name:
  680. fc = rcf.get( 'mpi.compiler.fc' )
  681. # or supporting openmp ?
  682. if rcf.get('par.openmp','bool') : fc = rcf.get( 'mpi.compiler.fc.openmp' )
  683. # f77 compiler, by default the same as fc:
  684. f77 = rcf.get( 'compiler.f77', default=fc )
  685. # assume linker is the same:
  686. linker = fc
  687. # Get compiler version too
  688. version = rcf.get('compiler.getversion_flag', default='--version')
  689. cmd=fc.split() # avoid space in fc (else problem without shell=True)
  690. cmd.append(version)
  691. # info ...
  692. logging.debug( ' fortran compiler : %s' % fc )
  693. try:
  694. fcv = go_subprocess.call(cmd)
  695. if len(fcv.stdout) > 0 : logging.debug( ' compiler version : %s' % fcv.stdout )
  696. if len(fcv.stderr) > 0 : logging.debug( ' compiler version : %s' % fcv.stderr )
  697. except:
  698. logging.debug( "You may set the correct key 'compiler.getversion_flag' to retrieve compiler's version.")
  699. logging.debug( ' linker : %s' % linker )
  700. return fc,f77,linker
  701. def Build_Make( rcf ) :
  702. """
  703. Make and install an executable.
  704. This script is called from the source directory.
  705. Arguments:
  706. rcf : dictionary with settings from rc file
  707. """
  708. # external
  709. import sys
  710. import os
  711. import logging
  712. # tools:
  713. import go
  714. import submit_tm5_tools
  715. # remove old object files ?
  716. clean = rcf.get('build.make.clean','bool',default=False)
  717. if clean :
  718. # info ...
  719. logging.debug( ' make clean ...' )
  720. # loop over all files:
  721. for f in os.listdir(os.curdir) :
  722. # remove ?
  723. if f.endswith('.o') or f.endswith('.mod') :
  724. # skip the most basic toolboxes ..
  725. if f.startswith('parray' ) : continue
  726. if f.startswith('file_hdf' ) : continue
  727. if f.startswith('mdf' ) : continue
  728. if f.startswith('file_grib') : continue
  729. if f.startswith('go' ) : continue
  730. if f.startswith('binas' ) : continue
  731. if f.startswith('num' ) : continue
  732. if f.startswith('phys' ) : continue
  733. if f.startswith('grid' ) : continue
  734. if f.startswith('tmm' ) : continue
  735. # info ...
  736. logging.debug( ' remove %s ...' % f )
  737. # remove:
  738. os.remove(f)
  739. # module dir ?
  740. mdir = rcf.get('compiler.mdir',default='None')
  741. if mdir != 'None' :
  742. # not present yet ? then create:
  743. if not os.path.exists( mdir ) : os.makedirs( mdir )
  744. # info ...
  745. logging.debug( ' make ...' )
  746. # number of jobs available for make:
  747. build_jobs = rcf.get( 'build.jobs', default='' )
  748. # get maker command; replace some keys:
  749. maker = rcf.get('maker').replace('%{build.jobs}',build_jobs)
  750. # get target executable:
  751. exe = rcf.get('build.make.exec')
  752. # full command:
  753. command = maker.split()+['-f','Makefile',exe]
  754. # Compile in the foreground or in the queue
  755. if rcf.get('build.make.submit','bool', default=False) and rcf.get('submit.to')=='queue':
  756. dummy = rcf.replace('submit.auto', False) # do not try to run while compiling!
  757. dummy = submit_tm5_tools.WriteAndSubmitBuildJob(rcf, command)
  758. else:
  759. logging.debug( ' run command: %s' % str(command) )
  760. p = go.subprocess.watch_call( command )
  761. return