123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844 |
- #! /usr/bin/env python
- import rc
- import os
- import sys
- import subprocess
- import glob
- from optparse import OptionParser
- import time
- import re
- import ttb_compare # For METHOD #2 in comparing restart. Comment for method #1
- import pdb
- """
- Module with THREE classes and ONE function.
- The 3 classes are:
- rctm5 : derived RcFile class, with specifics for TM5. Requires the
- tools/ttb/bin/rc.py for its raw option.
- tm5_test : class associated to a list of rc files.
- Has method to compare output restart from two runs associated
- to two of the rc files.
- LL : set of LoadLeveler specific functions (tested only with ECMWF
- implementation only). **OBSOLETE**
- --------------------------------------------------------------------------------
- The function 'testtm' (which is run if module is called as a script) is an
- example on how to use the classes defined here. It takes one or two input(s),
- which must be TM5 rc filenames:
- if two : run both cases and compare final restarts
-
- if one : run three cases (no mpi, 4, and 10 tasks), by modifying
- par.ntask, and compare their final restarts
- OR
- run two cases (w/ and w/o intermediate restart), by modifying
- jobstep.length, and compare their final restarts
- --------------------------------------------------------------------------------
- In a module you would do:
- import tm5_test
- tm5_test.testtm( ['file1.rc'], mpi=True, tm6=True )
- tm5_test.testtm( ['file1.rc', 'file2.rc'], new=True )
- At the command line, the same calls would be:
- $> tm5_test.py -m6 file1.rc
- $> tm5_test.py -n file1.rc file2.rc
- See:
- $> tm5_test.py -h
-
- """
- #////////////////////////////////////////////////////////
- # LoadLeveler specific functions (check run, get timing..)
- #////////////////////////////////////////////////////////
- class LL(object):
- """
- FIXME: should inherited rctm5 object => then no need for rootname at
- initialization
- """
-
- def __init__(self, rootname):
- self.root = rootname
- self.err=(''.join([self.root,'_init.err']),
- ''.join([self.root,'_run.err'] ),
- ''.join([self.root,'_done.err']) )
- # basic check on existence of the run (wait a bit)
- if not os.path.isfile(self.err[0]):
- time.sleep(10)
- if not os.path.isfile(self.err[0]):
- print "Run not started..."
- raise Exception
- def clean_jobs(self):
- """
- simply remove the log files
- """
-
- def check_jobs(self):
- """
- check completion of each 3 steps of a run
- """
- # INIT
- while self.isRunning(0): time.sleep(10)
- if not self.step_success(0):
- print self.root, " : FAIL at init step"
- raise Exception
- # RUN
- while self.isRunning(1): time.sleep(10)
- if not self.step_success(1):
- print self.root, " : FAIL at run step"
- raise Exception
- # DONE
- while self.isRunning(2): time.sleep(10)
- if not self.step_success(2):
- print self.root, " : FAIL at done step"
- raise Exception
-
-
- def step_success(self, step=0, verbose=False):
- """
- Look for 'exit_code=X' (if any) in *err file from a
- loadleveler job step, and return True if success, False
- else
- """
- ff = glob.glob(self.err[step])
- status = False
-
- if not len(ff):
- if verbose : print '\t',"No file :" + self.err[step]
- else:
- ffo=open(ff[0],'r')
- found=False
- for line in ffo:
- match=re.search('.*exit_code=(\d+)',line)
- if match:
- found=True
- if match.group(1) != '0':
- if verbose:print '\t', 'Error = '+match.group(1)
- else:
- status=True
- if verbose:print ' Succes = '+match.group(1)
-
- if not found: # catches memory out-of-range submit
- if verbose:print ' Error = unknown'
- ffo.close()
- return status
-
-
- def step_get_timing(self, step=0, verbose=False):
- """
- return timing as a tuple:
- ( elapsed time [s], cpu time [s], cpu time [hh:mm:ss],
- cost [system billing units] )
- from a finished jobstep from Loadleveler. If the *err file
- associated to the step is not found, just return 0,0,0,0
- """
- ff = glob.glob(self.err[step])
-
- regex=(
- '^ *Elapsed: *(\d+\.\d+) *sec',
- '^ *CPU Tot: *(\d+\.\d+) *sec',
- '.*\\+(\d{2}:\d{2}:\d{2})',
- '^ *System Billing Units .*= *(\d+\.\d+)'
- )
-
- elapsed, cpu, cpuf, bill=0,0,0,0
-
- if not len(ff):
- if verbose : print " No file :" + self.err[step]
- else:
- ffo=open(ff[0],'r')
- found=False
- for line in ffo:
- for k,r in enumerate(regex):
- match=re.search(r,line)
- if match:
- if k == 0: elapsed=match.group(1)
- if k == 1: cpu=match.group(1)
- if k == 2: cpuf=match.group(1)
- if k == 3: bill=match.group(1)
- ffo.close()
-
- return elapsed, cpu, cpuf, bill
-
-
- def isRunning(self, step=0):
- """
- returns True if step is running, False else
- """
-
- ff = glob.glob(self.err[step])
- if not len(ff):
- print "File not found:", self.err[step]
-
- # get job id
- match=None
- while not match:
- ffo=open(ff[0],'r')
- regex = ''.join(['c2a.*\.\d+\.', str(step)])
- for line in ffo:
- match = re.search(regex, line)
- if match:
- idr=match.group(0)
- break
-
- ffo.close()
- if not match: time.sleep(5) # if file opened too early
-
- # get status
- command = ['llq', '-f', '%st', idr]
- pr = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- out, err = pr.communicate()
- check=re.match('ST\n--\n(..)\n', out)
- if check :
- status=check.group(1)
- #print " status of job "+idr+" : "+status
- # if Idle, Running, Pending, almost completed, not queued yet, or Starting
- if status in ['R ','P ','I ', 'CP','ST', 'NQ']:
- return True
- else:
- return False
- else:
- return False
-
- #////////////////////////////////////////////////////////
- # Derived RcFile class for TM5
- #////////////////////////////////////////////////////////
- class rctm5(rc.RcFile):
- """
- Derived RcFile class that adds 'run', 'checkrun', 'clean' and a
- 'convert2nc3' methods.
-
- Add the following attributes (derived or existing in the rc dico but used a lot):
- self.rundone : T/F
- self.status : '', 'crashed', 'running'
- self.runtype : 'foreground', 'queue'
- self.region1 : name of first region (eg: 'glb600x400')
- self.restart : restart file in netCDF-4 format
- self.restart3 : restart file in netCDF-3 format
- self.timestamp : 'startdate_enddate' string used in mmix, budget,... filenames
- self.logcomp : name of log of setup_tm5 script
- self.rundir : run directory
- self.ok : tm5.ok fully qualified filename
-
- Also expands path of filename at init.
- """
-
- def __init__(self, filename, raw=False):
- rc.RcFile.__init__(self,os.path.expanduser(filename), raw=raw)
- self.setfilenames()
- self.rundone = False
- self.status = 'unknown'
- self.runtype = self.get('submit.to')
- self.basic_checkrun(verbose=False)
-
- def setfilenames(self):
- try:
- # restart filenames (original in netCDF 4 and converted to nc-3)
- outrestart = self.get('restart.write.dir' )
- etime = self.get('timerange.end' )
- hres = self.get('my.region1' )
- etime = etime.split()
- ymd = ''.join(etime[0].split('-'))
- hhmm = ''.join(etime[1][:5].split(':'))
- hh = ''.join(etime[1][:3].split(':'))
- fname = ''.join(["TM5_restart_", ymd, "_", hhmm, "_", hres, ".nc"])
-
- self.region1 = hres
- self.restart = os.path.join(outrestart, fname)
- self.restart3 = os.path.join(outrestart, ''.join([fname,"3"]))
-
- # repeat for start time, and get YYYYMMDDHH_YYYYMMDDHH string
- # used in mmix, jstat filenames (useful for runs with ONE job only)
- stime = self.get('timerange.start' )
- stime = stime.split()
- symd = ''.join(stime[0].split('-'))
- shhmm = ''.join(stime[1][:5].split(':'))
- shh = ''.join(etime[1][:3].split(':'))
-
- self.timestamp = ''.join([symd, shh, "_", ymd, hh])
- # rundir, tm5.ok, ...
- self.rundir = self.get('my.run.dir')
- self.ok = os.path.join(self.rundir,'tm5.ok')
- except:
- self.restart = ""
- self.restart3 = ""
- self.ok=''
-
- # Setup_tm5 script log (compilation if any)
- self.logcomp = os.path.join(os.curdir,
- os.path.splitext(self.filename)[0]+'.out')
- def display(self):
- """
- print basic info about tm5-rc obj.
- """
- print "RC file :", self.filename
- print "run dir :", self.get('my.run.dir')
- print "end restart :", self.restart
- print " ...exists :", os.path.isfile(self.restart)
- print "status :", self.status
- print "fg/bg/queue :", self.runtype
- print "log compil. :", self.logcomp
- print "--------------------------"
-
- def run(self, force=False, clean=False, queue=True):
- """
- Call setup_tm5, if final restart does not exist.
- If 'force', then runs even of the restart exists.
- If 'clean', re-compile everything ('build' dir is removed).
- If 'queue', use the queue manager, else run with the setting in the rc file.
- """
- if queue : self.runtype = "queue"
- tosubmit = force or (not os.path.isfile(self.restart))
-
- if tosubmit:
- command = [os.path.join(os.curdir,'setup_tm5'),
- self.filename,'-s']
-
- if queue :
- command.append("-q")
- #OLD # ------ loadleveler @ ECMWF specific (begin) ------
- #OLD # Remove any old log files (so .check_job will work)
- #OLD runid = self.get('my.basename')
- #OLD rundir = self.get('my.run.dir')
- #OLD mask = os.path.join(rundir,''.join([runid,'_[0-9][0-9][0-9]_*.err']))
- #OLD
- #OLD for f in glob.glob(mask):
- #OLD #print " removing "+f
- #OLD os.remove(f)
- #OLD
- #OLD # ------ loadleveler @ ECMWF specific (end) ------
-
- if clean : command.append("-n")
-
- print "submitting run for "+ self.filename
- fo=open(self.logcomp,'w')
- retcode = subprocess.call( command, stdout=fo, stderr=subprocess.STDOUT)
- fo.close()
-
- if retcode != 0 :
- print "compilation failed. See: ", self.logcomp
- self.status = 'crashed'
- self.rundone = True
- raise Exception
- else:
- print "submit ok"
- self.status = 'running'
- self.rundone = False
- else:
- print 'skipping run for '+ self.filename+' (final restart already exists)'
- self.status = 'done'
- self.rundone = True
- def convert2nc3(self):
- """
- Goal : modifying restart files so we can use 'cmp' on them.
-
- If we were dealing with netCDF-3, taking off the TimeStamp
- attribute from netCDF files is usually enough. But TM5 writes
- restart files in netCDF-4
- """
- # IF netcdf 3 then
- # command = ['ncatted', '-a TimeStamp,global,d,c,"a"', '-h', self.restart]
- # IF netcdf 4, convert to netcdf 3, without adding to history
- # attribute [could use nccopy if available]
-
- command = ['ncks', '-3', '-h', self.restart, self.restart3]
- if os.path.exists(self.restart) == True:
- if os.path.exists(self.restart3) == False:
- retcode = subprocess.call( command )
- if retcode != 0 :
- print command
- print "Conversion to netCDF 3 failed"
- raise Exception
- else:
- print "Restart converted to netCDF-3"
- else:
- print "Restart already converted to netCDF-3"
- else:
- print "No restart file to touch"
- def get_runtime(self):
- """
- simple print/return some runtimes for foreground run
- """
- regex = (
- '00] root *(\d+\.\d+)',
- '00] init *(\d+\.\d+)',
- '00] step init *(\d+\.\d+)',
- '00] step run *(\d+\.\d+)',
- '00] tmm readfield 2D *(\d+\.\d+)',
- '00] tmm readfield 3D *(\d+\.\d+)',
- '00] other *(\d+\.\d+)'
- )
- zeros=[0]*len(regex)
- if not self.rundone :
- print "run not submitted: No timing available."
- return zeros
- if self.runtype == 'foreground':
- try:
- logfile=open(self.logcomp,'r')
- except:
- print "no log file: No timing available."
- return zeros
- stat=[]
- for line in logfile:
- for k,r in enumerate(regex):
- klm=-1
- match = re.search(r, line)
- if match:
- print line,
- stat.append(match.group(1))
- klm=k
- if (klm+1) == len(regex) : break
- logfile.close()
- return stat
- else:
- # LoadLeveler case
- print "timing not directly available for LoadLeveler. See \
- checkrun for how-to"
- return zeros
-
- def checkrun(self, nowait=False):
- """
- Should return once a run is completely done. Already accounts for
- multiple jobsteps, and catches most crashes (as long as they give
- an error in log file). Now should be platform independent and works
- if run is in the foreground... where it is a bit overkill.
- """
- print "checking run for "+self.filename
-
- #if self.rundone :
- # print " restart already exists"
- # return
-
- rundir = self.get('my.run.dir')
- runid = self.get('my.basename')
- #--------------------
- # LOOP thru jobsteps
- #--------------------
- islast = False
- rcs=[]
- rc_exclude=[]
- while not islast:
- # get a newer rc file
- while not rcs :
- time.sleep(1)
- mask = ''.join([runid,'_[0-9][0-9][0-9].rc'])
- rcs = glob.glob(os.path.join(rundir,mask))
- if rc_exclude :
- for r in rc_exclude:
- if r in rcs: rcs.remove(r)
- rc_exclude.extend(rcs)
-
- # in case of older files around in the first pass
- newest = max(rcs, key=lambda x: os.stat(x).st_mtime)
- orc = rc.RcFile(newest)
- rcs=[]
- # step number id (001, 002, ...)
- find = re.search(r"_([0-9]{3})\.rc$", newest)
- if find:
- idnb=find.group(1)
- else:
- print "problem with RE to find jobstep number"
- raise Exception
- root = os.path.join(rundir,''.join([runid,'_',idnb]))
- # last chunk ?
- islast = ( orc.get('timerange.end') ==
- orc.get('jobstep.timerange.end') )
- if islast:
- print " checking last jobstep:", newest
- else:
- print " checking itermediate jobstep:", newest
- # check run
- #pdb.set_trace()
- if self.runtype == 'foreground':
- self.rundone = True
- if not os.path.exists(self.restart) : raise Exception
- timing=self.get_runtime()
- else:
- # ------ loadleveler @ ECMWF specific (begin) ------
- try:
- ll=LL(root)
- except:
- print "Problem with LoadLeveler object init"
- raise Exception
- ll.check_jobs()
- self.rundone = True
- print ll.step_get_timing(1)
- # ------ loadleveler @ ECMWF specific (end) ------
-
- # IF not using loadleveler at ECMWF, you can comment the
- # loadleveler lines above, and uncomment the following ones. That
- # just assumes a run never crashes, and wait for last restart:
-
- #while os.path.exists(self.restart) == False: time.sleep(10)
- #print " restart found"
- #
- ## including extra security to make sure restart is closed..
- #ok = os.path.join(rundir,'tm5.ok')
- #while os.path.exists(ok) == False: time.sleep(10)
- def basic_checkrun(self, verbose=True):
- """
- Check if a run is successfully terminated by checking the
- existence of the tm5.ok file and final restart file.
- Note this is not bullet proof: if between legs and final restart
- remains from a previous run.
- """
- if verbose: print "basic run check for "+self.filename
-
- if os.path.exists(self.ok) and os.path.exists(self.restart):
- if verbose: print "run sucessfully terminated"
- if verbose: print "--------------------------"
- self.rundone = True
- return True
- else:
- if verbose: print "run not done or crashed"
- if verbose: print "--------------------------"
- return False
-
- def cleanup(self, full=True, verbose=True):
- if verbose: print "cleaning up : ",self.filename
- # Minimal
- if os.path.isfile(self.restart3) : os.remove(self.restart3)
- # Full
- if full:
- if os.path.isfile(self.restart) : os.remove(self.restart)
- if os.path.isfile(self.logcomp) : os.remove(self.logcomp)
- # Empty rundir. Output and profiling are left in their
- # own directory (if different from the rundir)
- rundir = self.get('my.run.dir')
- if os.path.exists(rundir):
- files = [ os.path.join(rundir, f) for f in os.listdir(rundir) if
- os.path.isfile(os.path.join(rundir, f))]
-
- for f in files: os.remove(f)
- self.rundone = False
- def get_output_list(self):
- # restart and log
- out=[self.restart, self.logcomp]
- out=[f for f in out if os.path.isfile(f)]
-
- # run dir
- rundir = self.get('my.run.dir')
- if os.path.exists(rundir):
- files = [ os.path.join(rundir, f) for f in os.listdir(rundir) if
- os.path.isfile(os.path.join(rundir, f))]
- out=out+files
- # output dir
- rundir = self.get('output.dir')
- if os.path.exists(rundir):
- files = [ os.path.join(rundir, f) for f in os.listdir(rundir) if
- os.path.isfile(os.path.join(rundir, f))]
- out=out+files
- # profile dir
- subdir = self.get('timing.output.subdir')
- rundir = os.path.join(rundir, subdir)
- if os.path.exists(rundir):
- files = [ os.path.join(rundir, f) for f in os.listdir(rundir) if
- os.path.isfile(os.path.join(rundir, f))]
- out=out+files
- return out
-
- #////////////////////////////////////////////////////////
- # TEST class for TM5
- #////////////////////////////////////////////////////////
- class tm5_test(object):
- def __init__(self, Rcfiles):
- if len(Rcfiles) < 2 :
- print "pass at least 2 rc files for comparison"
- raise Exception
-
- self.rc=[]
- for fname in Rcfiles: self.rc.append( rctm5(fname) )
-
- def comp_restart(self, ind=[0,1], clean=False, queue=False):
- method=2 # 1 = Unix cmp ; 2 = tools/ttb/bin/ttb_compare.py
-
- # for now, can compare 2 runs only
- if len(ind) != 2 :
- print "requires 2 file index for comparison"
- raise Exception
- # same?
- if self.rc[ind[0]].restart == self.rc[ind[1]].restart:
- print "same path-to-file/restart-file in both cases !"
- print "\n SUCCESS"
- return 0
-
- # Submit (allows for concomittant runs in the queue)
- for k in ind: self.rc[k].run(clean=clean,queue=queue)
- # Wait for run end and do post-processing if any
- okrun = True
- for klm in ind:
- try:
- self.rc[klm].checkrun()
- if (method == 1): self.rc[klm].convert2nc3()
- except:
- print "\n FAILED run :", self.rc[klm].filename
- okrun = False
- if not okrun:
- print "\n FAILED - comparison aborted"
- return 1
- # COMPARE
- if method == 1:
-
- # METHOD 1 : binary comparison of restart files converted to
- # netCDF-3
- command = ['cmp', '-s', self.rc[ind[0]].restart3, self.rc[ind[1]].restart3 ]
- print "comparing:"
- print " ", self.rc[ind[0]].restart3
- print " ", self.rc[ind[1]].restart3
- retcode = subprocess.call( command )
- if method == 2:
-
- # METHOD #2 : if required python libraries are available, you can
- # also use TTB's ttb_compare.py module
- try :
- ttb_compare.df_files( self.rc[ind[0]].restart, self.rc[ind[1]].restart )
- retcode=0
- except :
- retcode=1
- if retcode != 0 :
- print "\n FAILED"
- else:
- print "\n SUCCESS"
- # minimal cleaning
- for rc in self.rc : rc.cleanup(full=False, verbose=False)
- return retcode
-
- def teardown(self):
- for rc in self.rc : rc.cleanup()
- #////////////////////////////////////////////////////////
- def testtm( args, new=False, queue=False, tm6=False, teardown=False, mpi=False, restart=False):
- narg=len(args)
- status = 0 # exit code
- if narg == 1:
- # Replacing "my.project.dir" key ensures that the build are
- # different (the key is mandatory), and that output and restart
- # (which are assumed to be defined below that dir), are in
- # different locations.
- rcobj=rctm5(args[0], raw=True)
- if teardown and not (restart or mpi):
- print """
- Nothing to clean up, no test being specified. Use
- also --mpi (-m) or --restart (-r)
- """
- if restart:
- rcno = 'onechunk.rc'
- rcyes = 'twochunks.rc'
-
- rcobj.replace('timerange.start', "2006-01-01 00:00:00")
- rcobj.replace('timerange.end', "2006-01-02 03:00:00")
- rcobj.replace('jobstep.length', 'inf')
- rcobj.replace('my.project.dir',' ${my.scratch}/TM5/test/onechunk')
- rcobj.WriteFile(rcno)
- rcobj.replace('jobstep.length', 1)
- rcobj.replace('my.project.dir', '${my.scratch}/TM5/test/twochunks')
- rcobj.WriteFile(rcyes)
- test = tm5_test( [rcyes, rcno] )
- if teardown :
- test.teardown()
- if os.path.isfile(rcyes): os.remove(rcyes)
- if os.path.isfile(rcno): os.remove(rcno)
- else:
- print "\nCompare add. intermediate restart:\n"
- status = status + test.comp_restart( clean=new, queue=queue )
- if mpi:
- rcnames=['one_proc.rc','four_proc.rc','ten_proc.rc']
- rcobj.replace('par.mpi','F')
- rcobj.replace('par.ntask',1)
- if tm6:
- rcobj.replace('par.nx',1)
- rcobj.replace('par.ny',1)
- rcobj.replace('my.project.dir','${my.scratch}/TM5/test/nompi')
- rcobj.WriteFile(rcnames[0])
-
- rcobj.replace('par.mpi','T')
- rcobj.replace('par.ntask',4)
- if tm6:
- rcobj.replace('par.nx',2)
- rcobj.replace('par.ny',2)
- rcobj.replace('my.project.dir','${my.scratch}/TM5/test/mpi4')
- rcobj.WriteFile(rcnames[1])
- rcobj.replace('par.mpi','T')
- rcobj.replace('par.ntask',10)
- if tm6:
- rcobj.replace('par.nx',2)
- rcobj.replace('par.ny',5)
- rcobj.replace('my.project.dir','${my.scratch}/TM5/test/mpi10')
- rcobj.WriteFile(rcnames[2])
- test = tm5_test( rcnames )
- if teardown :
- test.teardown()
- for rc in filter(lambda x: os.path.isfile(x), rcnames):
- os.remove(rc)
- else:
- print "\nCompare no-mpi and 4-procs-mpi runs:\n"
- status = status + test.comp_restart([0,1], clean=new, queue=queue)
-
- print "\nCompare 4-procs-mpi and 10-procs-mpi runs:\n"
- status = status + test.comp_restart([1,2], clean=new, queue=queue)
-
- print "\nCompare no-mpi and 10-procs-mpi runs:\n"
- status = status + test.comp_restart([0,2], queue=queue)
-
-
- elif narg == 2:
- test = tm5_test(args)
-
- if teardown :
- test.teardown()
- else:
- print "\nCompare \n"+args[0]+"\n and \n"+args[1]+"\n"
- status = status + test.comp_restart( clean=new, queue=queue )
-
- else:
- print "requires 1 or 2 rc file argument(s), not ", narg
- status=1
-
- return status
- #////////////////////////////////////////////////////////
- if __name__ == "__main__":
- parser = OptionParser(usage='%prog [options] rcfile_1 [rcfile_2]')
- parser.add_option("-t", "--teardown", action="store_true", dest="teardown",
- help="remove restart, files in rundir & compilation log")
- parser.add_option("-n", "--new", action="store_true", dest="new",
- help="recompile everything fresh (a la realclean)")
- parser.add_option("-q", "--queue", action="store_true", dest="queue",
- help="submit job to queue instead of foreground")
- parser.add_option("-m", "--mpi", action="store_true", dest="mpi",
- help="test if different #procs gives same result")
- parser.add_option("-r", "--restart", action="store_true", dest="restart",
- help="test if cutting a run in two smaller chunks gives the same result")
- parser.add_option("-6", "--tm6", action="store_true", dest="tm6",
- help="indicates that rc file is for a tm6 model, use only for --mpi test.")
- options, args = parser.parse_args()
-
- sys.exit( testtm( args,
- new=options.new, queue=options.queue,
- tm6=options.tm6, teardown=options.teardown,
- mpi=options.mpi, restart=options.restart) )
|