123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943 |
- """
- PYCASSO User Scripts
- Do not change the arguments of the defined routines, only their content !
- """
- #-------------------------------------------------
- # arguments and options
- #-------------------------------------------------
- def DefineOptions( parser ) :
- """
- Usage : DefineOptions( parser )
- Define options supported by user scripts.
- Arugments:
- parser : optparse object
- """
- # define flag to clean source code:
- parser.add_option( "-c", "--clean",
- help="Remove high level object and module files before "
- "compilation. Low level objects from for example the "
- "'file_hdf' sources are not removed to speedup "
- "re-compilation of the model. "
- "To have all objects removed, use the '--new' option "
- "to create a complete new build; in older scripts "
- "an option '-C' or '--clean-all' was defined for this.",
- dest="clean", action="store_true", default=False )
- parser.add_option( "--steps", help="'stages list' (can contains: init, run, done, all) that overwrites job.steps from expert rc file.",
- dest="stages")
- # Useful options for coupling TM5 to EC-Earth
- parser.add_option("--time-start", help="'yyyy-mm-dd hh:mn:ss' that overwrites timerange.start of rc file.",
- dest="time_start")
- parser.add_option("--time-final", help="'yyyy-mm-dd hh:mn:ss' that overwrites timerange.end of rc file.",
- dest="time_end")
- parser.add_option("--istart", help="overwrite istart of rc file. No effect if empty string ''", dest="istart")
- return
- # *
- def StoreOptions( settings, values ) :
- """
- Add the parsed flags ('values') to the 'settings' dictionary.
- The values have data fields with names defined by 'dest'
- in the previous calls to 'parser.add_option' .
- """
- # translate options into a dictionairy if they should
- # replace rcfile values:
- if values.clean : settings['build.make.clean'] = True
- if values.stages != None : settings['job.steps'] = values.stages
- # Useful for EC-Earth
- if values.time_start != None : settings['timerange.start'] = values.time_start
- if values.time_end != None : settings['timerange.end' ] = values.time_end
- if values.time_start != None : settings['jobstep.timerange.start'] = values.time_start
- if values.time_end != None : settings['jobstep.timerange.end' ] = values.time_end
- if values.istart != None :
- if len(values.istart): settings['istart'] = values.istart
- return
- #-------------------------------------------------
- # source
- #-------------------------------------------------
- def Build_FlagGroups( rcf, basic=False ) :
- """
- Return list of compiler flag groups to be used.
- """
- # default :
- flaggroups = ['default','real8']
- # add mpi ?
- if rcf.get('par.mpi','bool') : flaggroups.append('mpi')
- # Get full list of TM flags
- line = rcf.get('build.configure.flags').split()
- # Add 'debug' and 'check-all' to basics group
- if 'check-all' in line:
- flaggroups += ['check-all']
- line.remove('check-all')
- if 'debug' in line:
- flaggroups += ['debug']
- line.remove('debug')
- # include not standard flags ?
- if not basic :
- # add openmp ?
- if rcf.get('par.openmp','bool') : flaggroups.append('openmp')
- flaggroups += line
- ## add adjoint ?
- #if rcf.get('var4d','bool') : flaggroups.append('adj')
- return flaggroups
- # ***
- def Build_Define( rcf, macro_group, mdefs ) :
- """
- Edit a list with macro's to be defined given
- the name of group of macro's and the other setings
- in the rcfile.
- """
- # external:
- import logging
- # info ...
- logging.info( ' user script Build_Define for macro group %s ...' % macro_group )
- # select on macro group name:
- if macro_group == 'tm5' :
- # macro to include checks on zooming;
- # required for zoom runs, but should be undefined
- # for runs without zooming to speedup the program:
- mac = 'with_zoom'
- # regions defined via a list in the rcfile ?
- if len(rcf.get('regions',default='')) > 0 :
- # number of regions:
- nregions = len(rcf.get('regions').split())
- else :
- # the 'old' method defines the grid via source files;
- # key 'source.nregions' from the rcfile is used to set the actual number:
- nregions_text = rcf.get('source.nregions')
- # check for special value:
- if nregions_text == 'nregions_max' :
- nregions = 999
- else :
- nregions = int(nregions_text)
- #endif
- #endif
- # zoom regions ? then
- if nregions > 1 :
- # define macro 'with_zoom' if not present yet:
- if mac not in mdefs :
- # add:
- mdefs.append( mac )
- # info ...
- logging.info( ' defined %s ...' % mac )
- #endif
- else :
- # no zooming, remove macro 'with_zoom' if present:
- if mac in mdefs :
- # remove:
- mdefs.remove( mac )
- # info ...
- logging.info( ' undefined %s ...' % mac )
- #endif
- #endif
- # macro's to enable MPI specific code:
- macs = ['MPI']
- # loop:
- for mac in macs :
- # MPI enabled ?
- if rcf.get('par.mpi','bool') :
- # define macro 'with_zoom' if not present yet:
- if mac not in mdefs :
- # add:
- mdefs.append( mac )
- # info ...
- logging.info( ' defined %s ...' % mac )
- else :
- # MPI not enabled, remove if necessary:
- if mac in mdefs :
- # add:
- mdefs.remove( mac )
- # info ...
- logging.info( ' undefined %s ...' % mac )
- return mdefs
- # ***
- def Build_Configure( rcf ) :
- """
- Configure a source code.
- This script is called from the source directory.
- Arguments:
- rcf : dictionairy with settings from rc file
- """
- # external
- import logging
- # info ...
- logging.info( ' user script Build_Configure ...' )
- # write grid definitions:
- Build_Configure_Grid( rcf )
- # check on depricated stuff ...
- Build_Configure_Check( rcf )
- return
- # *
- def Build_Configure_Grid( rcf ) :
- """
- Write source files for grid definition.
- """
- # external:
- import logging
- # info ...
- logging.info( ' user script Build_Configure_Grid ...' )
- # regions are defined either by a list of region names ('regions') ,
- # or the older method using 'source.nregions' and 'dims_grid.h' :
- if len(rcf.get('regions',default='')) > 0 :
- # write all source files:
- Build_Configure_Grid__regions( rcf )
- elif rcf.has_key('source.nregions') :
- # write only number of regions to include file:
- Build_Configure_Grid__nregions( rcf )
- else :
- logging.error( 'could not extract number of regions from rcfile settings;' )
- logging.error( 'either "regions" or "source.nregions" should be defined' )
- raise Exception
- return
- # *
- def Build_Configure_Grid__nregions( rcf ) :
- """
- Write 'dims_grid.h' from rcfile settings.
- """
- # modules:
- import logging
- #~ this sometimes fails if module was just copied to work directory ...
- #import pycasso_tools
- #~ seems to work:
- import imp
- fp,pathname,description = imp.find_module( 'pycasso_tools' )
- pycasso_tools = imp.load_module( 'pycasso_tools', fp, pathname, description )
- # info ...
- logging.info( ' user script Build_Configure_Grid__nregions ...' )
- # which file to create ?
- srcfile = 'dims_grid.h'
- # info ...
- logging.info( ' create %s ...' % srcfile )
- # number of regions; could be the name 'nregions_max', thus read as string:
- source_nregions = rcf.get('source.nregions')
- # fill lines:
- lines = []
- lines.append( '!\n' )
- lines.append( '! Define actual number of regions.\n' )
- lines.append( '! Included by \'dims_grid.F90\'.\n' )
- lines.append( '!\n' )
- lines.append( 'integer, parameter :: nregions = %s\n' % source_nregions )
- # update file if necessary ...
- pycasso_tools.update_text_file( srcfile, lines )
- #enddef Build_Configure_Grid__nregions
- # *
- def Build_Configure_Grid__regions( rcf, env={} ) :
- """
- Write 'dims_grid.F90' from rcfile settings.
- """
- # modules:
- import logging
- # tools:
- import rc
- #~ this sometimes fails if module was just copied to work directory ...
- #import pycasso_tools
- #~ seems to work:
- import imp
- fp,pathname,description = imp.find_module( 'pycasso_tools' )
- pycasso_tools = imp.load_module( 'pycasso_tools', fp, pathname, description )
- # info ...
- logging.info( ' user script Build_Configure_Grid__regions ...' )
- # provided filename or dictionairy?
- if type(rcf) == str :
- # read settings:
- rcf = rc.RcFile( rcf, env=env )
- #endif
- # which file to create ?
- srcfile = 'dims_grid.F90'
- # different versions could be made, depending on the release (former cycle);
- # get the target release, use ininite number ('latest' release) as default:
- build_release = rcf.get( 'build.configure.release', 'float', default=999.9 )
- # info ...
- logging.info( ' create %s ...' % srcfile )
- # model regions:
- regions = rcf.get('regions').split()
- # old or new style ...
- if build_release < 3.0 :
- # actual number:
- nregions = len(regions)
- # maximum length of grid names:
- len_region_name = max(map(len,regions))
- # other ...
- maxref = rcf.get('region.maxref')
- dx = rcf.get('region.dx')
- dy = rcf.get('region.dy')
- dz = rcf.get('region.dz')
- # start with empty file:
- lines = []
- lines.append( '!#################################################################\n' )
- lines.append( '!\n' )
- lines.append( '! Grids.\n' )
- lines.append( '!\n' )
- lines.append( '!### macro\'s #####################################################\n' )
- lines.append( '!\n' )
- lines.append( '#include "tm5.inc"\n' )
- lines.append( '!\n' )
- lines.append( '!#################################################################\n' )
- lines.append( '\n' )
- lines.append( 'module dims_grid\n' )
- lines.append( '\n' )
- lines.append( ' implicit none\n' )
- lines.append( ' \n' )
- lines.append( ' ! --- in/out ------------------------------\n' )
- lines.append( ' \n' )
- lines.append( ' public\n' )
- lines.append( ' \n' )
- lines.append( ' \n' )
- lines.append( ' ! --- const -------------------------------\n' )
- lines.append( ' \n' )
- lines.append( ' \n' )
- lines.append( ' ! Basic model definition: resolution etc. including some routines\n' )
- lines.append( ' ! to fill the data structure.\n' )
- lines.append( '\n' )
- lines.append( ' ! basic (coarsest) resolution in degrees for x and y (dz default 1.0)\n' )
- lines.append( '\n' )
- lines.append( ' real, parameter :: dx = %s\n' % dx )
- lines.append( ' real, parameter :: dy = %s\n' % dy )
- lines.append( ' real, parameter :: dz = %s\n' % dz )
- lines.append( '\n' )
- lines.append( '\n' )
- lines.append( ' ! Maximum number of zoom regions, \n' )
- lines.append( ' ! including the basic (coarsest grid) region;\n' )
- lines.append( ' ! arrays are allocated for each of these regions:\n' )
- lines.append( ' integer, parameter :: nregions_max = %i\n' % nregions )
- lines.append( ' \n' )
- lines.append( ' ! Actual number of zoom regions,\n' )
- lines.append( ' ! during testing this could be set to 1 to quickly run the model.\n' )
- lines.append( ' integer, parameter :: nregions = %s\n' % nregions )
- lines.append( '\n' )
- lines.append( ' ! region_name is used to recognise the METEO files\n' )
- lines.append( ' ! region_name is also used in the HDF output file name\n' )
- lines.append( ' ! region 1 should always be the global domain\n' )
- lines.append( '\n' )
- lines.append( ' integer, parameter :: len_region_name = %i\n' % len_region_name )
- lines.append( ' character(len=len_region_name), parameter :: region_name(1:nregions) = &\n' )
- line = ' (/ '
- for i in range(len(regions)) :
- if i > 0 : line = line + ', '
- fmt = "'%%-%is'" % len_region_name
- line = line + ( fmt % regions[i] )
- #endfor
- lines.append( line+'/)\n' )
- lines.append( '\n' )
- lines.append( ' ! coordinates (in degrees) for each region:\n' )
- lines.append( ' ! xcyc = 1 if the region has cyclic x-boundary conditions\n' )
- lines.append( ' ! touch_np = 1 if region touches the north pole\n' )
- lines.append( ' ! touch_sp = 1 if region touches the south pole\n' )
- lines.append( ' ! xbeg : the westmost border of the region\n' )
- lines.append( ' ! xend : the eastmost border of the region\n' )
- lines.append( ' ! ybeg : the southmost border of the region\n' )
- lines.append( ' ! yend : the northmost border of the region\n' )
- lines.append( '\n' )
- fields = ['xcyc','touch_np','touch_sp','xbeg','xend','ybeg','yend','im','jm']
- for ifield in range(len(fields)) :
- field = fields[ifield]
- line = ' integer, parameter :: %-8s(nregions) = (/ ' % field
- for iregion in range(len(regions)) :
- region = regions[iregion]
- if iregion > 0 : line = line + ', '
- val = rcf.get( 'region.%s.%s' % (region,field) )
- line = line + ( '%4i' % int(val) )
- #endfor
- lines.append( line+' /)\n' )
- #endfor
- lines.append( '\n' )
- lines.append( '\n' )
- lines.append( ' ! maximum refinement factor (can be arbitrary in principle):\n' )
- lines.append( '\n' )
- lines.append( ' integer, parameter :: maxref = %s\n' % maxref )
- lines.append( '\n' )
- lines.append( ' ! refinement factors for each region (<= maxref)\n' )
- lines.append( ' ! tref may differ from xref/yref. In the current \n' )
- lines.append( ' ! implementation it should be 1,2,4,6,...\n' )
- lines.append( '\n' )
- fields = ['xref','yref','zref','tref']
- for ifield in range(len(fields)) :
- field = fields[ifield]
- line = ' integer, parameter :: %s(0:nregions) = (/ 1' % field
- for i in range(nregions) :
- #if i > 0 : line = line + ', '
- line = line + ', '
- val = rcf.get( 'region.%s.%s' % (regions[i],field) )
- line = line + ( '%4i' % int(val) )
- #endfor
- lines.append( line+' /)\n' )
- #endfor
- lines.append( '\n' )
- lines.append( ' ! Define the parent of each region. \n' )
- lines.append( ' ! Global region 1 should have parent 0 (globe single cell);\n' )
- lines.append( ' ! global surface region should have parent 1 (global region).\n' )
- line = ' integer, parameter :: parent(nregions) = (/ '
- for i in range(nregions) :
- if i > 0 : line = line + ', '
- val = rcf.get( 'region.%s.parent' % regions[i] )
- if val == 'globe' :
- ireg = 0
- else :
- ireg = regions.index(val) + 1
- #endif
- line = line + ( '%i' % ireg )
- #endfor
- lines.append( line+' /)\n' )
- lines.append( '\n' )
- lines.append( 'end module dims_grid\n' )
- else : # release 3.0 and higher
- # maximum number of 'zooming' model regions:
- nregions_max = len(regions)
- # add global surface grid if necessary:
- region_glbsfc = rcf.get('region.glbsfc')
- if len(region_glbsfc) > 0 : regions = regions + [region_glbsfc]
- # all regions:
- nregions_all = len(regions)
- # start with global grid:
- regions = [rcf.get('region.globe')] + regions
- # actual number is the maximum ...
- nregions = 'nregions_max'
- # maximum length of grid names:
- len_region_name = max(map(len,regions))
- # other ...
- maxref = rcf.get('region.maxref')
- dx = rcf.get('region.dx')
- dy = rcf.get('region.dy')
- dz = rcf.get('region.dz')
- # fill lines:
- lines = []
- lines.append( '!#################################################################\n' )
- lines.append( '!\n' )
- lines.append( '! Grids.\n' )
- lines.append( '!\n' )
- lines.append( '!### macro\'s #####################################################\n' )
- lines.append( '!\n' )
- lines.append( '#include "tm5.inc"\n' )
- lines.append( '!\n' )
- lines.append( '!#################################################################\n' )
- lines.append( '\n' )
- lines.append( 'module dims_grid\n' )
- lines.append( '\n' )
- lines.append( ' implicit none\n' )
- lines.append( ' \n' )
- lines.append( ' ! --- in/out ------------------------------\n' )
- lines.append( ' \n' )
- lines.append( ' public\n' )
- lines.append( ' \n' )
- lines.append( ' \n' )
- lines.append( ' ! --- const -------------------------------\n' )
- lines.append( ' \n' )
- lines.append( ' \n' )
- lines.append( ' ! Basic model definition: resolution etc. including some routines\n' )
- lines.append( ' ! to fill the data structure.\n' )
- lines.append( '\n' )
- lines.append( ' ! basic (coarsest) resolution in degrees for x and y (dz default 1.0)\n' )
- lines.append( '\n' )
- lines.append( ' real, parameter :: dx = %s\n' % dx )
- lines.append( ' real, parameter :: dy = %s\n' % dy )
- lines.append( ' real, parameter :: dz = %s\n' % dz )
- lines.append( '\n' )
- lines.append( '\n' )
- lines.append( ' ! Maximum number of zoom regions, \n' )
- lines.append( ' ! including the basic (coarsest grid) region;\n' )
- lines.append( ' ! arrays are allocated for each of these regions:\n' )
- lines.append( ' integer, parameter :: nregions_max = %i\n' % nregions_max )
- lines.append( ' \n' )
- if len(region_glbsfc) > 0 :
- lines.append( ' ! extra grid:\n' )
- lines.append( ' integer, parameter :: nregions_all = nregions_max + 1\n' )
- lines.append( ' integer, parameter :: iglbsfc = nregions_max + 1\n' )
- else :
- lines.append( ' ! no extra surface grid, use the global model grid for this:\n' )
- lines.append( ' integer, parameter :: nregions_all = nregions_max\n' )
- lines.append( ' integer, parameter :: iglbsfc = 1\n' )
- lines.append( '\n' )
- lines.append( ' ! Actual number of zoom regions,\n' )
- lines.append( ' ! during testing this could be set to 1 to quickly run the model.\n' )
- lines.append( ' integer, parameter :: nregions = %s\n' % nregions )
- lines.append( '\n' )
- lines.append( ' ! region_name is used to recognise the METEO files\n' )
- lines.append( ' ! region_name is also used in the HDF output file name\n' )
- lines.append( ' ! region 1 should always be the global domain\n' )
- lines.append( '\n' )
- lines.append( ' integer, parameter :: len_region_name = %i\n' % len_region_name )
- lines.append( ' character(len=len_region_name), parameter :: region_name(0:nregions_all) = &\n' )
- line = ' (/ '
- for i in range(len(regions)) :
- if i > 0 : line = line + ', '
- fmt = "'%%-%is'" % len_region_name
- line = line + ( fmt % regions[i] )
- lines.append( line+'/)\n' )
- lines.append( '\n' )
- lines.append( ' ! coordinates (in degrees) for each region:\n' )
- lines.append( ' ! xcyc = 1 if the region has cyclic x-boundary conditions\n' )
- lines.append( ' ! touch_np = 1 if region touches the north pole\n' )
- lines.append( ' ! touch_sp = 1 if region touches the south pole\n' )
- lines.append( ' ! xbeg : the westmost border of the region\n' )
- lines.append( ' ! xend : the eastmost border of the region\n' )
- lines.append( ' ! ybeg : the southmost border of the region\n' )
- lines.append( ' ! yend : the northmost border of the region\n' )
- lines.append( '\n' )
- fields = ['xcyc','touch_np','touch_sp','xbeg','xend','ybeg','yend','im','jm']
- for ifield in range(len(fields)) :
- field = fields[ifield]
- line = ' integer, parameter :: %-8s(0:nregions_all) = (/ ' % field
- for iregion in range(len(regions)) :
- region = regions[iregion]
- if iregion > 0 : line = line + ', '
- val = rcf.get( 'region.%s.%s' % (region,field) )
- line = line + ( '%4i' % int(val) )
- lines.append( line+' /)\n' )
- lines.append( '\n' )
- lines.append( '\n' )
- lines.append( ' ! maximum refinement factor (can be arbitrary in principle):\n' )
- lines.append( '\n' )
- lines.append( ' integer, parameter :: maxref = %s\n' % maxref )
- lines.append( '\n' )
- lines.append( ' ! refinement factors for each region (<= maxref)\n' )
- lines.append( ' ! tref may differ from xref/yref. In the current \n' )
- lines.append( ' ! implementation it should be 1,2,4,6,...\n' )
- lines.append( '\n' )
- fields = ['xref','yref','zref','tref']
- for ifield in range(len(fields)) :
- field = fields[ifield]
- line = ' integer, parameter :: %s(0:nregions_max) = (/ ' % field
- for i in range(0,nregions_max+1) :
- if i > 0 : line = line + ', '
- val = rcf.get( 'region.%s.%s' % (regions[i],field) )
- line = line + ( '%4i' % int(val) )
- lines.append( line+' /)\n' )
- lines.append( '\n' )
- lines.append( ' ! Define the parent of each region. \n' )
- lines.append( ' ! Global region 1 should have parent 0 (globe single cell);\n' )
- lines.append( ' ! global surface region should have parent 1 (global region).\n' )
- line = ' integer, parameter :: parent(1:nregions_all) = (/ '
- for i in range(1,nregions_all+1) :
- if i > 1 : line = line + ', '
- val = rcf.get( 'region.%s.parent' % regions[i] )
- # check ...
- if val not in regions :
- logging.error( 'parent "%s" of region %i "%s" not in (extended) region list : %s' % (val,i,regions[i],regions) )
- raise ValueError
- ireg = regions.index(val)
- line = line + ( '%i' % ireg )
- lines.append( line+' /)\n' )
- lines.append( '\n' )
- lines.append( 'end module dims_grid\n' )
- #endif
- # update file if necessary ...
- pycasso_tools.update_text_file( srcfile, lines )
- #enddef Build_Configure_Grid__regions
- # *
- def Build_Configure_Check( rcf ) :
- """
- Check source file for undesired features.
- """
- # external:
- import logging
- import os
- import fnmatch
- # info ...
- logging.info( ' user script Build_Configure_Check ...' )
- # keywords for checks to be performed:
- checknames = rcf.get( 'build.configure.checks', default='' )
- # empty ? then leave:
- if len(checknames) == 0 : return
- # error or just warnings ?
- with_error = rcf.get( 'build.configure.checks.error', 'bool', default=False )
- # set flag:
- any_warning = False
- # list files:
- srcfiles = os.listdir( os.curdir )
- srcfiles.sort()
- # loop over checks:
- for checkname in checknames.split() :
- # paterns:
- test_msg = rcf.get( 'build.configure.check.%s.msg' % checkname )
- test_files = rcf.get( 'build.configure.check.%s.files' % checkname ).split()
- test_skip = rcf.get( 'build.configure.check.%s.skip' % checkname ).split()
- test_line = rcf.get( 'build.configure.check.%s.test' % checkname )
- test_help = rcf.get( 'build.configure.check.%s.help' % checkname )
- # set flags:
- matching_files = False
- # loop over files:
- for srcfile in srcfiles :
- # match with patern ?
- match = False
- for pat in test_files :
- match = match or fnmatch.fnmatch(srcfile,pat)
- if match : break
- if not match : continue
- # ... except if the name matches other patterns:
- match = False
- for pat in test_skip :
- match = match or fnmatch.fnmatch(srcfile,pat)
- if match : break
- if match : continue
- # read file:
- f = open( srcfile, 'r+', encoding="utf-8" )
- logging.info( ' %s' % ('Reading: '+srcfile) )
- lines = f.readlines()
- f.close()
- # search for something that is there, or something that is not there ...
- if test_line.startswith('not') :
- # by default no match:
- match = False
- # loop over lines:
- for line in lines :
- # test on this line:
- match = match or (not eval( test_line ))
- # try next file after first match ...
- if match : break
- # check next file if the requested code was found:
- if match : continue
- # revert:
- match = not match
- else :
- # by default no match:
- match = False
- # loop over lines:
- for line in lines[0:20] :
- # test on this line:
- match = match or eval( test_line )
- # leave after first match ...
- if match : break
- # found something ?
- if match :
- # info ...
- if not matching_files : logging.warning( ' %s : [found]' % test_msg )
- logging.warning( ' %s' % srcfile )
- # reset flags:
- matching_files = True
- any_warning = True
- # info ...
- if matching_files :
- # display error message ?
- if with_error :
- # display help text; split at '\n' for newlines:
- for helpline in test_help.split('\\n') : logging.warning(helpline)
- else :
- # no warnings for this test ...
- logging.info( ' %s [none ]' % test_msg )
- # check for unknown macro's ?
- checkname = 'unknown_macro'
- flag = rcf.get( 'build.configure.check.%s' % checkname )
- if flag :
- # settings:
- test_msg = rcf.get( 'build.configure.check.%s.msg' % checkname )
- # names of macro groups:
- macgroups = rcf.get( 'build.configure.macro.groups' ).split()
- # collect all supported macro's:
- macall = []
- for macgroup in macgroups :
- macs = rcf.get( 'build.configure.macro.%s.all' % macgroup ).split()
- macall = macall + macs
- # flag ...
- logged_msg = False
- # loop over files:
- for srcfile in srcfiles :
- # read file (only if not *.mod, *.o or directory):
- if os.path.isdir(srcfile) : continue
- if fnmatch.fnmatch(srcfile,"*.mod") : continue
- if fnmatch.fnmatch(srcfile,"*.o") : continue
- if fnmatch.fnmatch(srcfile,"*.x") : continue
- with open( srcfile, 'r+', encoding="utf-8" ) as f:
- lines = f.readlines()
- # flags:
- logged_srcfile = False
- # loop over lines:
- for iline in range(len(lines)) :
- # current:
- line = lines[iline].strip()
- # macro test ?
- if line.startswith('#ifdef') or line.startswith('#ifndef') :
- # second element of line is macro name:
- mac = line.split()[1].strip()
- # not supported ?
- if mac not in macall :
- # test description if not done yet:
- if not logged_msg :
- logging.info( ' %s' % test_msg )
- logged_msg = True
- #endif
- # intro if necessary:
- if not logged_srcfile :
- logging.error( ' unsupported macro(s) in %s :' % srcfile )
- logged_srcfile = True
- #endif
- # line number and content:
- logging.error( ' %6i : %s' % (iline,line) )
- # set flag:
- any_warning = True
- # jippy ...
- if not logged_msg :
- # no warnings for this test ...
- logging.info( ' %s [none ]' % test_msg )
- # break ?
- if any_warning and with_error :
- logging.error( 'some source code checks failed; break' )
- logging.error( '(set "build.configure.checks.error : False" in the expert.rc to avoid this error)' )
- raise Exception
- return
- # ***
- def Build_Compiler( rcf ) :
- """
- Set compiler and linker names.
- Usually it is enough to read the name from the rcfile,
- but some compiler families have aliases for compilation with
- MPI or OpenMP enabled.
- Arguments:
- rcf : dictionary with settings from rc file
- Return values:
- fc,linker
- """
- # external
- import logging
- import go_subprocess
- # info ...
- logging.info( ' user script Build_Compiler ...' )
- # extract compiler name:
- fc = rcf.get('compiler.fc')
- # or supporting openmp ?
- if rcf.get('par.openmp','bool') : fc = rcf.get( 'compiler.fc.openmp' )
- # or with mpi support ?
- if rcf.get('par.mpi','bool') :
- # extract compiler name:
- fc = rcf.get( 'mpi.compiler.fc' )
- # or supporting openmp ?
- if rcf.get('par.openmp','bool') : fc = rcf.get( 'mpi.compiler.fc.openmp' )
- # f77 compiler, by default the same as fc:
- f77 = rcf.get( 'compiler.f77', default=fc )
- # assume linker is the same:
- linker = fc
- # Get compiler version too
- version = rcf.get('compiler.getversion_flag', default='--version')
- cmd=fc.split() # avoid space in fc (else problem without shell=True)
- cmd.append(version)
- # info ...
- logging.debug( ' fortran compiler : %s' % fc )
- try:
- fcv = go_subprocess.call(cmd)
- if len(fcv.stdout) > 0 : logging.debug( ' compiler version : %s' % fcv.stdout )
- if len(fcv.stderr) > 0 : logging.debug( ' compiler version : %s' % fcv.stderr )
- except:
- logging.debug( "You may set the correct key 'compiler.getversion_flag' to retrieve compiler's version.")
- logging.debug( ' linker : %s' % linker )
- return fc,f77,linker
- def Build_Make( rcf ) :
- """
- Make and install an executable.
- This script is called from the source directory.
- Arguments:
- rcf : dictionary with settings from rc file
- """
- # external
- import sys
- import os
- import logging
- # tools:
- import go
- import submit_tm5_tools
- # remove old object files ?
- clean = rcf.get('build.make.clean','bool',default=False)
- if clean :
- # info ...
- logging.debug( ' make clean ...' )
- # loop over all files:
- for f in os.listdir(os.curdir) :
- # remove ?
- if f.endswith('.o') or f.endswith('.mod') :
- # skip the most basic toolboxes ..
- if f.startswith('parray' ) : continue
- if f.startswith('file_hdf' ) : continue
- if f.startswith('mdf' ) : continue
- if f.startswith('file_grib') : continue
- if f.startswith('go' ) : continue
- if f.startswith('binas' ) : continue
- if f.startswith('num' ) : continue
- if f.startswith('phys' ) : continue
- if f.startswith('grid' ) : continue
- if f.startswith('tmm' ) : continue
- # info ...
- logging.debug( ' remove %s ...' % f )
- # remove:
- os.remove(f)
- # module dir ?
- mdir = rcf.get('compiler.mdir',default='None')
- if mdir != 'None' :
- # not present yet ? then create:
- if not os.path.exists( mdir ) : os.makedirs( mdir )
- # info ...
- logging.debug( ' make ...' )
- # number of jobs available for make:
- build_jobs = rcf.get( 'build.jobs', default='' )
- # get maker command; replace some keys:
- maker = rcf.get('maker').replace('%{build.jobs}',build_jobs)
- # get target executable:
- exe = rcf.get('build.make.exec')
- # full command:
- command = maker.split()+['-f','Makefile',exe]
- # Compile in the foreground or in the queue
- if rcf.get('build.make.submit','bool', default=False) and rcf.get('submit.to')=='queue':
- dummy = rcf.replace('submit.auto', False) # do not try to run while compiling!
- dummy = submit_tm5_tools.WriteAndSubmitBuildJob(rcf, command)
- else:
- logging.debug( ' run command: %s' % str(command) )
- p = go.subprocess.watch_call( command )
- return
|