pycasso_user_scripts_tm5.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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. # modules:
  196. import logging
  197. #~ this sometimes fails if module was just copied to work directory ...
  198. #import pycasso_tools
  199. #~ seems to work:
  200. import imp
  201. fp,pathname,description = imp.find_module( 'pycasso_tools' )
  202. pycasso_tools = imp.load_module( 'pycasso_tools', fp, pathname, description )
  203. # info ...
  204. logging.info( ' user script Build_Configure_Grid__nregions ...' )
  205. # which file to create ?
  206. srcfile = 'dims_grid.h'
  207. # info ...
  208. logging.info( ' create %s ...' % srcfile )
  209. # number of regions; could be the name 'nregions_max', thus read as string:
  210. source_nregions = rcf.get('source.nregions')
  211. # fill lines:
  212. lines = []
  213. lines.append( '!\n' )
  214. lines.append( '! Define actual number of regions.\n' )
  215. lines.append( '! Included by \'dims_grid.F90\'.\n' )
  216. lines.append( '!\n' )
  217. lines.append( 'integer, parameter :: nregions = %s\n' % source_nregions )
  218. # update file if necessary ...
  219. pycasso_tools.update_text_file( srcfile, lines )
  220. #enddef Build_Configure_Grid__nregions
  221. # *
  222. def Build_Configure_Grid__regions( rcf, env={} ) :
  223. """
  224. Write 'dims_grid.F90' from rcfile settings.
  225. """
  226. # modules:
  227. import logging
  228. # tools:
  229. import rc
  230. #~ this sometimes fails if module was just copied to work directory ...
  231. #import pycasso_tools
  232. #~ seems to work:
  233. import imp
  234. fp,pathname,description = imp.find_module( 'pycasso_tools' )
  235. pycasso_tools = imp.load_module( 'pycasso_tools', fp, pathname, description )
  236. # info ...
  237. logging.info( ' user script Build_Configure_Grid__regions ...' )
  238. # provided filename or dictionairy?
  239. if type(rcf) == str :
  240. # read settings:
  241. rcf = rc.RcFile( rcf, env=env )
  242. #endif
  243. # which file to create ?
  244. srcfile = 'dims_grid.F90'
  245. # different versions could be made, depending on the release (former cycle);
  246. # get the target release, use ininite number ('latest' release) as default:
  247. build_release = rcf.get( 'build.configure.release', 'float', default=999.9 )
  248. # info ...
  249. logging.info( ' create %s ...' % srcfile )
  250. # model regions:
  251. regions = rcf.get('regions').split()
  252. # old or new style ...
  253. if build_release < 3.0 :
  254. # actual number:
  255. nregions = len(regions)
  256. # maximum length of grid names:
  257. len_region_name = max(map(len,regions))
  258. # other ...
  259. maxref = rcf.get('region.maxref')
  260. dx = rcf.get('region.dx')
  261. dy = rcf.get('region.dy')
  262. dz = rcf.get('region.dz')
  263. # start with empty file:
  264. lines = []
  265. lines.append( '!#################################################################\n' )
  266. lines.append( '!\n' )
  267. lines.append( '! Grids.\n' )
  268. lines.append( '!\n' )
  269. lines.append( '!### macro\'s #####################################################\n' )
  270. lines.append( '!\n' )
  271. lines.append( '#include "tm5.inc"\n' )
  272. lines.append( '!\n' )
  273. lines.append( '!#################################################################\n' )
  274. lines.append( '\n' )
  275. lines.append( 'module dims_grid\n' )
  276. lines.append( '\n' )
  277. lines.append( ' implicit none\n' )
  278. lines.append( ' \n' )
  279. lines.append( ' ! --- in/out ------------------------------\n' )
  280. lines.append( ' \n' )
  281. lines.append( ' public\n' )
  282. lines.append( ' \n' )
  283. lines.append( ' \n' )
  284. lines.append( ' ! --- const -------------------------------\n' )
  285. lines.append( ' \n' )
  286. lines.append( ' \n' )
  287. lines.append( ' ! Basic model definition: resolution etc. including some routines\n' )
  288. lines.append( ' ! to fill the data structure.\n' )
  289. lines.append( '\n' )
  290. lines.append( ' ! basic (coarsest) resolution in degrees for x and y (dz default 1.0)\n' )
  291. lines.append( '\n' )
  292. lines.append( ' real, parameter :: dx = %s\n' % dx )
  293. lines.append( ' real, parameter :: dy = %s\n' % dy )
  294. lines.append( ' real, parameter :: dz = %s\n' % dz )
  295. lines.append( '\n' )
  296. lines.append( '\n' )
  297. lines.append( ' ! Maximum number of zoom regions, \n' )
  298. lines.append( ' ! including the basic (coarsest grid) region;\n' )
  299. lines.append( ' ! arrays are allocated for each of these regions:\n' )
  300. lines.append( ' integer, parameter :: nregions_max = %i\n' % nregions )
  301. lines.append( ' \n' )
  302. lines.append( ' ! Actual number of zoom regions,\n' )
  303. lines.append( ' ! during testing this could be set to 1 to quickly run the model.\n' )
  304. lines.append( ' integer, parameter :: nregions = %s\n' % nregions )
  305. lines.append( '\n' )
  306. lines.append( ' ! region_name is used to recognise the METEO files\n' )
  307. lines.append( ' ! region_name is also used in the HDF output file name\n' )
  308. lines.append( ' ! region 1 should always be the global domain\n' )
  309. lines.append( '\n' )
  310. lines.append( ' integer, parameter :: len_region_name = %i\n' % len_region_name )
  311. lines.append( ' character(len=len_region_name), parameter :: region_name(1:nregions) = &\n' )
  312. line = ' (/ '
  313. for i in range(len(regions)) :
  314. if i > 0 : line = line + ', '
  315. fmt = "'%%-%is'" % len_region_name
  316. line = line + ( fmt % regions[i] )
  317. #endfor
  318. lines.append( line+'/)\n' )
  319. lines.append( '\n' )
  320. lines.append( ' ! coordinates (in degrees) for each region:\n' )
  321. lines.append( ' ! xcyc = 1 if the region has cyclic x-boundary conditions\n' )
  322. lines.append( ' ! touch_np = 1 if region touches the north pole\n' )
  323. lines.append( ' ! touch_sp = 1 if region touches the south pole\n' )
  324. lines.append( ' ! xbeg : the westmost border of the region\n' )
  325. lines.append( ' ! xend : the eastmost border of the region\n' )
  326. lines.append( ' ! ybeg : the southmost border of the region\n' )
  327. lines.append( ' ! yend : the northmost border of the region\n' )
  328. lines.append( '\n' )
  329. fields = ['xcyc','touch_np','touch_sp','xbeg','xend','ybeg','yend','im','jm']
  330. for ifield in range(len(fields)) :
  331. field = fields[ifield]
  332. line = ' integer, parameter :: %-8s(nregions) = (/ ' % field
  333. for iregion in range(len(regions)) :
  334. region = regions[iregion]
  335. if iregion > 0 : line = line + ', '
  336. val = rcf.get( 'region.%s.%s' % (region,field) )
  337. line = line + ( '%4i' % int(val) )
  338. #endfor
  339. lines.append( line+' /)\n' )
  340. #endfor
  341. lines.append( '\n' )
  342. lines.append( '\n' )
  343. lines.append( ' ! maximum refinement factor (can be arbitrary in principle):\n' )
  344. lines.append( '\n' )
  345. lines.append( ' integer, parameter :: maxref = %s\n' % maxref )
  346. lines.append( '\n' )
  347. lines.append( ' ! refinement factors for each region (<= maxref)\n' )
  348. lines.append( ' ! tref may differ from xref/yref. In the current \n' )
  349. lines.append( ' ! implementation it should be 1,2,4,6,...\n' )
  350. lines.append( '\n' )
  351. fields = ['xref','yref','zref','tref']
  352. for ifield in range(len(fields)) :
  353. field = fields[ifield]
  354. line = ' integer, parameter :: %s(0:nregions) = (/ 1' % field
  355. for i in range(nregions) :
  356. #if i > 0 : line = line + ', '
  357. line = line + ', '
  358. val = rcf.get( 'region.%s.%s' % (regions[i],field) )
  359. line = line + ( '%4i' % int(val) )
  360. #endfor
  361. lines.append( line+' /)\n' )
  362. #endfor
  363. lines.append( '\n' )
  364. lines.append( ' ! Define the parent of each region. \n' )
  365. lines.append( ' ! Global region 1 should have parent 0 (globe single cell);\n' )
  366. lines.append( ' ! global surface region should have parent 1 (global region).\n' )
  367. line = ' integer, parameter :: parent(nregions) = (/ '
  368. for i in range(nregions) :
  369. if i > 0 : line = line + ', '
  370. val = rcf.get( 'region.%s.parent' % regions[i] )
  371. if val == 'globe' :
  372. ireg = 0
  373. else :
  374. ireg = regions.index(val) + 1
  375. #endif
  376. line = line + ( '%i' % ireg )
  377. #endfor
  378. lines.append( line+' /)\n' )
  379. lines.append( '\n' )
  380. lines.append( 'end module dims_grid\n' )
  381. else : # release 3.0 and higher
  382. # maximum number of 'zooming' model regions:
  383. nregions_max = len(regions)
  384. # add global surface grid if necessary:
  385. region_glbsfc = rcf.get('region.glbsfc')
  386. if len(region_glbsfc) > 0 : regions = regions + [region_glbsfc]
  387. # all regions:
  388. nregions_all = len(regions)
  389. # start with global grid:
  390. regions = [rcf.get('region.globe')] + regions
  391. # actual number is the maximum ...
  392. nregions = 'nregions_max'
  393. # maximum length of grid names:
  394. len_region_name = max(map(len,regions))
  395. # other ...
  396. maxref = rcf.get('region.maxref')
  397. dx = rcf.get('region.dx')
  398. dy = rcf.get('region.dy')
  399. dz = rcf.get('region.dz')
  400. # fill lines:
  401. lines = []
  402. lines.append( '!#################################################################\n' )
  403. lines.append( '!\n' )
  404. lines.append( '! Grids.\n' )
  405. lines.append( '!\n' )
  406. lines.append( '!### macro\'s #####################################################\n' )
  407. lines.append( '!\n' )
  408. lines.append( '#include "tm5.inc"\n' )
  409. lines.append( '!\n' )
  410. lines.append( '!#################################################################\n' )
  411. lines.append( '\n' )
  412. lines.append( 'module dims_grid\n' )
  413. lines.append( '\n' )
  414. lines.append( ' implicit none\n' )
  415. lines.append( ' \n' )
  416. lines.append( ' ! --- in/out ------------------------------\n' )
  417. lines.append( ' \n' )
  418. lines.append( ' public\n' )
  419. lines.append( ' \n' )
  420. lines.append( ' \n' )
  421. lines.append( ' ! --- const -------------------------------\n' )
  422. lines.append( ' \n' )
  423. lines.append( ' \n' )
  424. lines.append( ' ! Basic model definition: resolution etc. including some routines\n' )
  425. lines.append( ' ! to fill the data structure.\n' )
  426. lines.append( '\n' )
  427. lines.append( ' ! basic (coarsest) resolution in degrees for x and y (dz default 1.0)\n' )
  428. lines.append( '\n' )
  429. lines.append( ' real, parameter :: dx = %s\n' % dx )
  430. lines.append( ' real, parameter :: dy = %s\n' % dy )
  431. lines.append( ' real, parameter :: dz = %s\n' % dz )
  432. lines.append( '\n' )
  433. lines.append( '\n' )
  434. lines.append( ' ! Maximum number of zoom regions, \n' )
  435. lines.append( ' ! including the basic (coarsest grid) region;\n' )
  436. lines.append( ' ! arrays are allocated for each of these regions:\n' )
  437. lines.append( ' integer, parameter :: nregions_max = %i\n' % nregions_max )
  438. lines.append( ' \n' )
  439. if len(region_glbsfc) > 0 :
  440. lines.append( ' ! extra grid:\n' )
  441. lines.append( ' integer, parameter :: nregions_all = nregions_max + 1\n' )
  442. lines.append( ' integer, parameter :: iglbsfc = nregions_max + 1\n' )
  443. else :
  444. lines.append( ' ! no extra surface grid, use the global model grid for this:\n' )
  445. lines.append( ' integer, parameter :: nregions_all = nregions_max\n' )
  446. lines.append( ' integer, parameter :: iglbsfc = 1\n' )
  447. lines.append( '\n' )
  448. lines.append( ' ! Actual number of zoom regions,\n' )
  449. lines.append( ' ! during testing this could be set to 1 to quickly run the model.\n' )
  450. lines.append( ' integer, parameter :: nregions = %s\n' % nregions )
  451. lines.append( '\n' )
  452. lines.append( ' ! region_name is used to recognise the METEO files\n' )
  453. lines.append( ' ! region_name is also used in the HDF output file name\n' )
  454. lines.append( ' ! region 1 should always be the global domain\n' )
  455. lines.append( '\n' )
  456. lines.append( ' integer, parameter :: len_region_name = %i\n' % len_region_name )
  457. lines.append( ' character(len=len_region_name), parameter :: region_name(0:nregions_all) = &\n' )
  458. line = ' (/ '
  459. for i in range(len(regions)) :
  460. if i > 0 : line = line + ', '
  461. fmt = "'%%-%is'" % len_region_name
  462. line = line + ( fmt % regions[i] )
  463. lines.append( line+'/)\n' )
  464. lines.append( '\n' )
  465. lines.append( ' ! coordinates (in degrees) for each region:\n' )
  466. lines.append( ' ! xcyc = 1 if the region has cyclic x-boundary conditions\n' )
  467. lines.append( ' ! touch_np = 1 if region touches the north pole\n' )
  468. lines.append( ' ! touch_sp = 1 if region touches the south pole\n' )
  469. lines.append( ' ! xbeg : the westmost border of the region\n' )
  470. lines.append( ' ! xend : the eastmost border of the region\n' )
  471. lines.append( ' ! ybeg : the southmost border of the region\n' )
  472. lines.append( ' ! yend : the northmost border of the region\n' )
  473. lines.append( '\n' )
  474. fields = ['xcyc','touch_np','touch_sp','xbeg','xend','ybeg','yend','im','jm']
  475. for ifield in range(len(fields)) :
  476. field = fields[ifield]
  477. line = ' integer, parameter :: %-8s(0:nregions_all) = (/ ' % field
  478. for iregion in range(len(regions)) :
  479. region = regions[iregion]
  480. if iregion > 0 : line = line + ', '
  481. val = rcf.get( 'region.%s.%s' % (region,field) )
  482. line = line + ( '%4i' % int(val) )
  483. lines.append( line+' /)\n' )
  484. lines.append( '\n' )
  485. lines.append( '\n' )
  486. lines.append( ' ! maximum refinement factor (can be arbitrary in principle):\n' )
  487. lines.append( '\n' )
  488. lines.append( ' integer, parameter :: maxref = %s\n' % maxref )
  489. lines.append( '\n' )
  490. lines.append( ' ! refinement factors for each region (<= maxref)\n' )
  491. lines.append( ' ! tref may differ from xref/yref. In the current \n' )
  492. lines.append( ' ! implementation it should be 1,2,4,6,...\n' )
  493. lines.append( '\n' )
  494. fields = ['xref','yref','zref','tref']
  495. for ifield in range(len(fields)) :
  496. field = fields[ifield]
  497. line = ' integer, parameter :: %s(0:nregions_max) = (/ ' % field
  498. for i in range(0,nregions_max+1) :
  499. if i > 0 : line = line + ', '
  500. val = rcf.get( 'region.%s.%s' % (regions[i],field) )
  501. line = line + ( '%4i' % int(val) )
  502. lines.append( line+' /)\n' )
  503. lines.append( '\n' )
  504. lines.append( ' ! Define the parent of each region. \n' )
  505. lines.append( ' ! Global region 1 should have parent 0 (globe single cell);\n' )
  506. lines.append( ' ! global surface region should have parent 1 (global region).\n' )
  507. line = ' integer, parameter :: parent(1:nregions_all) = (/ '
  508. for i in range(1,nregions_all+1) :
  509. if i > 1 : line = line + ', '
  510. val = rcf.get( 'region.%s.parent' % regions[i] )
  511. # check ...
  512. if val not in regions :
  513. logging.error( 'parent "%s" of region %i "%s" not in (extended) region list : %s' % (val,i,regions[i],regions) )
  514. raise ValueError
  515. ireg = regions.index(val)
  516. line = line + ( '%i' % ireg )
  517. lines.append( line+' /)\n' )
  518. lines.append( '\n' )
  519. lines.append( 'end module dims_grid\n' )
  520. #endif
  521. # update file if necessary ...
  522. pycasso_tools.update_text_file( srcfile, lines )
  523. #enddef Build_Configure_Grid__regions
  524. # *
  525. def Build_Configure_Check( rcf ) :
  526. """
  527. Check source file for undesired features.
  528. """
  529. # external:
  530. import logging
  531. import os
  532. import fnmatch
  533. # info ...
  534. logging.info( ' user script Build_Configure_Check ...' )
  535. # keywords for checks to be performed:
  536. checknames = rcf.get( 'build.configure.checks', default='' )
  537. # empty ? then leave:
  538. if len(checknames) == 0 : return
  539. # error or just warnings ?
  540. with_error = rcf.get( 'build.configure.checks.error', 'bool', default=False )
  541. # set flag:
  542. any_warning = False
  543. # list files:
  544. srcfiles = os.listdir( os.curdir )
  545. srcfiles.sort()
  546. # loop over checks:
  547. for checkname in checknames.split() :
  548. # paterns:
  549. test_msg = rcf.get( 'build.configure.check.%s.msg' % checkname )
  550. test_files = rcf.get( 'build.configure.check.%s.files' % checkname ).split()
  551. test_skip = rcf.get( 'build.configure.check.%s.skip' % checkname ).split()
  552. test_line = rcf.get( 'build.configure.check.%s.test' % checkname )
  553. test_help = rcf.get( 'build.configure.check.%s.help' % checkname )
  554. # set flags:
  555. matching_files = False
  556. # loop over files:
  557. for srcfile in srcfiles :
  558. # match with patern ?
  559. match = False
  560. for pat in test_files :
  561. match = match or fnmatch.fnmatch(srcfile,pat)
  562. if match : break
  563. if not match : continue
  564. # ... except if the name matches other patterns:
  565. match = False
  566. for pat in test_skip :
  567. match = match or fnmatch.fnmatch(srcfile,pat)
  568. if match : break
  569. if match : continue
  570. # read file:
  571. f = open( srcfile, 'r+', encoding="utf-8" )
  572. logging.info( ' %s' % ('Reading: '+srcfile) )
  573. lines = f.readlines()
  574. f.close()
  575. # search for something that is there, or something that is not there ...
  576. if test_line.startswith('not') :
  577. # by default no match:
  578. match = False
  579. # loop over lines:
  580. for line in lines :
  581. # test on this line:
  582. match = match or (not eval( test_line ))
  583. # try next file after first match ...
  584. if match : break
  585. # check next file if the requested code was found:
  586. if match : continue
  587. # revert:
  588. match = not match
  589. else :
  590. # by default no match:
  591. match = False
  592. # loop over lines:
  593. for line in lines[0:20] :
  594. # test on this line:
  595. match = match or eval( test_line )
  596. # leave after first match ...
  597. if match : break
  598. # found something ?
  599. if match :
  600. # info ...
  601. if not matching_files : logging.warning( ' %s : [found]' % test_msg )
  602. logging.warning( ' %s' % srcfile )
  603. # reset flags:
  604. matching_files = True
  605. any_warning = True
  606. # info ...
  607. if matching_files :
  608. # display error message ?
  609. if with_error :
  610. # display help text; split at '\n' for newlines:
  611. for helpline in test_help.split('\\n') : logging.warning(helpline)
  612. else :
  613. # no warnings for this test ...
  614. logging.info( ' %s [none ]' % test_msg )
  615. # check for unknown macro's ?
  616. checkname = 'unknown_macro'
  617. flag = rcf.get( 'build.configure.check.%s' % checkname )
  618. if flag :
  619. # settings:
  620. test_msg = rcf.get( 'build.configure.check.%s.msg' % checkname )
  621. # names of macro groups:
  622. macgroups = rcf.get( 'build.configure.macro.groups' ).split()
  623. # collect all supported macro's:
  624. macall = []
  625. for macgroup in macgroups :
  626. macs = rcf.get( 'build.configure.macro.%s.all' % macgroup ).split()
  627. macall = macall + macs
  628. # flag ...
  629. logged_msg = False
  630. # loop over files:
  631. for srcfile in srcfiles :
  632. # read file (only if not *.mod, *.o or directory):
  633. if os.path.isdir(srcfile) : continue
  634. if fnmatch.fnmatch(srcfile,"*.mod") : continue
  635. if fnmatch.fnmatch(srcfile,"*.o") : continue
  636. if fnmatch.fnmatch(srcfile,"*.x") : continue
  637. with open( srcfile, 'r+', encoding="utf-8" ) as f:
  638. lines = f.readlines()
  639. # flags:
  640. logged_srcfile = False
  641. # loop over lines:
  642. for iline in range(len(lines)) :
  643. # current:
  644. line = lines[iline].strip()
  645. # macro test ?
  646. if line.startswith('#ifdef') or line.startswith('#ifndef') :
  647. # second element of line is macro name:
  648. mac = line.split()[1].strip()
  649. # not supported ?
  650. if mac not in macall :
  651. # test description if not done yet:
  652. if not logged_msg :
  653. logging.info( ' %s' % test_msg )
  654. logged_msg = True
  655. #endif
  656. # intro if necessary:
  657. if not logged_srcfile :
  658. logging.error( ' unsupported macro(s) in %s :' % srcfile )
  659. logged_srcfile = True
  660. #endif
  661. # line number and content:
  662. logging.error( ' %6i : %s' % (iline,line) )
  663. # set flag:
  664. any_warning = True
  665. # jippy ...
  666. if not logged_msg :
  667. # no warnings for this test ...
  668. logging.info( ' %s [none ]' % test_msg )
  669. # break ?
  670. if any_warning and with_error :
  671. logging.error( 'some source code checks failed; break' )
  672. logging.error( '(set "build.configure.checks.error : False" in the expert.rc to avoid this error)' )
  673. raise Exception
  674. return
  675. # ***
  676. def Build_Compiler( rcf ) :
  677. """
  678. Set compiler and linker names.
  679. Usually it is enough to read the name from the rcfile,
  680. but some compiler families have aliases for compilation with
  681. MPI or OpenMP enabled.
  682. Arguments:
  683. rcf : dictionary with settings from rc file
  684. Return values:
  685. fc,linker
  686. """
  687. # external
  688. import logging
  689. import go_subprocess
  690. # info ...
  691. logging.info( ' user script Build_Compiler ...' )
  692. # extract compiler name:
  693. fc = rcf.get('compiler.fc')
  694. # or supporting openmp ?
  695. if rcf.get('par.openmp','bool') : fc = rcf.get( 'compiler.fc.openmp' )
  696. # or with mpi support ?
  697. if rcf.get('par.mpi','bool') :
  698. # extract compiler name:
  699. fc = rcf.get( 'mpi.compiler.fc' )
  700. # or supporting openmp ?
  701. if rcf.get('par.openmp','bool') : fc = rcf.get( 'mpi.compiler.fc.openmp' )
  702. # f77 compiler, by default the same as fc:
  703. f77 = rcf.get( 'compiler.f77', default=fc )
  704. # assume linker is the same:
  705. linker = fc
  706. # Get compiler version too
  707. version = rcf.get('compiler.getversion_flag', default='--version')
  708. cmd=fc.split() # avoid space in fc (else problem without shell=True)
  709. cmd.append(version)
  710. # info ...
  711. logging.debug( ' fortran compiler : %s' % fc )
  712. try:
  713. fcv = go_subprocess.call(cmd)
  714. if len(fcv.stdout) > 0 : logging.debug( ' compiler version : %s' % fcv.stdout )
  715. if len(fcv.stderr) > 0 : logging.debug( ' compiler version : %s' % fcv.stderr )
  716. except:
  717. logging.debug( "You may set the correct key 'compiler.getversion_flag' to retrieve compiler's version.")
  718. logging.debug( ' linker : %s' % linker )
  719. return fc,f77,linker
  720. def Build_Make( rcf ) :
  721. """
  722. Make and install an executable.
  723. This script is called from the source directory.
  724. Arguments:
  725. rcf : dictionary with settings from rc file
  726. """
  727. # external
  728. import sys
  729. import os
  730. import logging
  731. # tools:
  732. import go
  733. import submit_tm5_tools
  734. # remove old object files ?
  735. clean = rcf.get('build.make.clean','bool',default=False)
  736. if clean :
  737. # info ...
  738. logging.debug( ' make clean ...' )
  739. # loop over all files:
  740. for f in os.listdir(os.curdir) :
  741. # remove ?
  742. if f.endswith('.o') or f.endswith('.mod') :
  743. # skip the most basic toolboxes ..
  744. if f.startswith('parray' ) : continue
  745. if f.startswith('file_hdf' ) : continue
  746. if f.startswith('mdf' ) : continue
  747. if f.startswith('file_grib') : continue
  748. if f.startswith('go' ) : continue
  749. if f.startswith('binas' ) : continue
  750. if f.startswith('num' ) : continue
  751. if f.startswith('phys' ) : continue
  752. if f.startswith('grid' ) : continue
  753. if f.startswith('tmm' ) : continue
  754. # info ...
  755. logging.debug( ' remove %s ...' % f )
  756. # remove:
  757. os.remove(f)
  758. # module dir ?
  759. mdir = rcf.get('compiler.mdir',default='None')
  760. if mdir != 'None' :
  761. # not present yet ? then create:
  762. if not os.path.exists( mdir ) : os.makedirs( mdir )
  763. # info ...
  764. logging.debug( ' make ...' )
  765. # number of jobs available for make:
  766. build_jobs = rcf.get( 'build.jobs', default='' )
  767. # get maker command; replace some keys:
  768. maker = rcf.get('maker').replace('%{build.jobs}',build_jobs)
  769. # get target executable:
  770. exe = rcf.get('build.make.exec')
  771. # full command:
  772. command = maker.split()+['-f','Makefile',exe]
  773. # Compile in the foreground or in the queue
  774. if rcf.get('build.make.submit','bool', default=False) and rcf.get('submit.to')=='queue':
  775. dummy = rcf.replace('submit.auto', False) # do not try to run while compiling!
  776. dummy = submit_tm5_tools.WriteAndSubmitBuildJob(rcf, command)
  777. else:
  778. logging.debug( ' run command: %s' % str(command) )
  779. p = go.subprocess.watch_call( command )
  780. return