Commit 37baecb4 authored by Peters, Wouter's avatar Peters, Wouter
Browse files

The da_initexit.py and das.py are now starting to us the new class based modules.

parent 4697e5cf
! Info on the data assimilation cycle ! Info on the data assimilation cycle
time.restart : False time.restart : False
time.start : 2005030500 time.start : 2005-03-05 00:00:00
time.finish : 2005030700 time.finish : 2005-03-07 00:00:00
time.cycle : 1 time.cycle : 1
time.nlag : 2 time.nlag : 2
dir.da_run : ${HOME}/tmp/test_da dir.da_run : ${HOME}/tmp/test_da
......
This diff is collapsed.
...@@ -8,9 +8,7 @@ Revision History: ...@@ -8,9 +8,7 @@ Revision History:
File created on 29 Sep 2009. File created on 29 Sep 2009.
""" """
import rc from da_initexit import CycleControl
from tools_da import ValidateRC
from tools_da import needed_rc_da_items
header = '\n\n *************************************** ' header = '\n\n *************************************** '
footer = ' *************************************** \n ' footer = ' *************************************** \n '
...@@ -20,139 +18,57 @@ validprocess=['jobstart','jobinput','sample','invert','propagate','resubmit','al ...@@ -20,139 +18,57 @@ validprocess=['jobstart','jobinput','sample','invert','propagate','resubmit','al
def JobStart(opts,args): def JobStart(opts,args):
""" Set up the job specific directory structure and create an expanded rc-file """ """ Set up the job specific directory structure and create an expanded rc-file """
import rc DaCycle = CycleControl(opts,args)
from da_initexit import StartRestartRecover
from tools_da import ParseTimes
from da_initexit import WriteRC
rc_da_shell = rc.read(args['rc']) DaCycle.Initialize()
# Add some useful variables to the rc-file dictionary return DaCycle
rc_da_shell['log'] = args["logfile"]
rc_da_shell['dir.da_submit'] = os.getcwd() def JobInput(CycleInfo):
rc_da_shell['da.crash.recover'] = '-r' in opts
rc_da_shell['verbose'] = '-v' in opts
dummy = ValidateRC(rc_da_shell,needed_rc_da_items)
# Figure out what to do: is this is a fresh start, a continuation, or a recover from crash
dummy = StartRestartRecover(rc_da_shell)
# Calculate DA system startdate, enddate, and finaldate from rc-file items
dummy = ParseTimes(rc_da_shell)
dummy = WriteRC(rc_da_shell,args['jobrcfilename'])
return rc_da_shell
def JobInput(args):
""" Set up the input data for the forward model: obs and parameters/fluxes""" """ Set up the input data for the forward model: obs and parameters/fluxes"""
from tools_da import PrepareObs from tools_da import PrepareObs
from tools_da import PrepareEnsemble from tools_da import PrepareEnsemble
from da_initexit import WriteRC
rc_da_shell = rc.read(args['jobrcfilename'])
dummy = ValidateRC(rc_da_shell,needed_rc_da_items) dummy = PrepareEnsemble(CycleInfo)
dummy = PrepareEnsemble(rc_da_shell) dummy = PrepareObs(CycleInfo,'forecast')
dummy = PrepareObs(rc_da_shell,'forecast')
dummy = WriteRC(rc_da_shell,args['jobrcfilename'])
return None return None
def Sample(args): def Sample(CycleInfo):
""" Sample the filter state for the inversion """ """ Sample the filter state for the inversion """
from da_initexit import WriteRC from tools_da import RunForecastModel
rc_da_shell = rc.read(args['jobrcfilename'])
dummy = ValidateRC(rc_da_shell,needed_rc_da_items)
dummy = ForwardRun(args,'forecast') dummy = RunForecastModel(CycleInfo,'forecast')
# Optionally, post-processing of the model ouptu can be added that deals for instance with # Optionally, post-processing of the model ouptu can be added that deals for instance with
# sub-sampling of time series, vertical averaging, etc. # sub-sampling of time series, vertical averaging, etc.
dummy = WriteRC(rc_da_shell,args['jobrcfilename'])
return None
def ForwardRun(args,runtype='forecast'):
""" Run the forward model from startdate to enddate """
from tools_da import SetInterval
from tools_da import RunForecastModel
from da_initexit import IOSaveData
from da_initexit import WriteRC
rc_da_shell = rc.read(args['jobrcfilename'])
dummy = ValidateRC(rc_da_shell,needed_rc_da_items)
dummy = SetInterval(rc_da_shell,runtype)
dummy = RunForecastModel(rc_da_shell)
dummy = WriteRC(rc_da_shell,args['jobrcfilename'])
return None return None
def Invert(args): def Invert(CycleInfo):
""" Perform the inverse calculation """ """ Perform the inverse calculation """
import tools_da import tools_da
from da_initexit import WriteRC
rc_da_shell = rc.read(args['jobrcfilename']) dummy = tools_da.Invert(CycleInfo)
dummy = ValidateRC(rc_da_shell,needed_rc_da_items)
dummy = tools_da.Invert(rc_da_shell)
dummy = WriteRC(rc_da_shell,args['jobrcfilename'])
return None return None
def Propagate(args): def Propagate(CycleInfo):
""" Propagate the filter state to the next step """ """ Propagate the filter state to the next step """
from da_initexit import WriteRC from tools_da import RunForecastModel
rc_da_shell = rc.read(args['jobrcfilename'])
dummy = ValidateRC(rc_da_shell,needed_rc_da_items)
# This is the advance of the modeled CO2 state. Optionally, routines can be added to advance the state vector (mean+covariance) # This is the advance of the modeled CO2 state. Optionally, routines can be added to advance the state vector (mean+covariance)
dummy = ForwardRun(args,'advance') dummy = RunForecastModel(CycleInfo,'advance')
dummy = WriteRC(rc_da_shell,args['jobrcfilename'])
return None return None
def SaveAndSubmit(args): def SaveAndSubmit(CycleInfo):
""" Save the model state and submit the next job """ """ Save the model state and submit the next job """
from da_initexit import IOSaveData
from da_initexit import WriteRC
from da_initexit import WriteNewRCfile
from da_initexit import SubmitNextCycle
rc_da_shell = rc.read(args['jobrcfilename'])
dummy = ValidateRC(rc_da_shell,needed_rc_da_items)
dummy = IOSaveData(rc_da_shell,io_option='store',save_option='full') dummy = CycleInfo.Finalize()
dummy = WriteNewRCfile(rc_da_shell)
dummy = SubmitNextCycle(rc_da_shell)
return None return None
...@@ -161,7 +77,9 @@ if __name__ == "__main__": ...@@ -161,7 +77,9 @@ if __name__ == "__main__":
import os import os
import logging import logging
import shutil import shutil
import subprocess
from tools_da import CleanUpCycle
from tools_da import ValidateOptsArgs
from tools_da import ParseOptions from tools_da import ParseOptions
from tools_da import StartLogger from tools_da import StartLogger
...@@ -169,90 +87,40 @@ if __name__ == "__main__": ...@@ -169,90 +87,40 @@ if __name__ == "__main__":
sys.path.append(os.getcwd()) sys.path.append(os.getcwd())
# Get name of logfile # Start a logger for all that happens from here on
dummy = StartLogger()
# Parse options from the command line
opts, args = ParseOptions() opts, args = ParseOptions()
if not args.has_key("logfile"): # Validate Options and arguments passed
msg = "There is no logfile specified on the command line. Using logfile=logfile.log"
args['logfile'] = 'logfile.log' opts,args = ValidateOptsArgs(opts,args)
logfile = args['logfile'] # Start the subprocesses
dummy = StartLogger(logfile=logfile)
msg = header+"starting JobStart"+footer ; logging.info(msg)
if not args.has_key("rc"): CycleInfo = JobStart(opts,args)
msg = "There is no rc-file specified on the command line. Please use rc=yourfile.rc" ; logging.error(msg)
raise IOError,msg #msg = header+"starting JobInput"+footer ; logging.info(msg)
elif not os.path.exists(args['rc']): #dummy = JobInput(CycleInfo)
msg = "The specified rc-file (%s) does not exist " % args['rc'] ; logging.error(msg)
raise IOError,msg msg = header+"starting Sample Taking"+footer ; logging.info(msg)
dummy = Sample(CycleInfo)
if not args.has_key("process"):
msg = "There is no execution process specified on the command line. Using default process=all" ; logging.error(msg) #msg = header+"starting Invert"+footer ; logging.info(msg)
args["process"] = 'all' #dummy = Invert(CycleInfo)
if not args["process"] in validprocess:
msg = "The specified execution process is not valid (%s). Please use one of %s"%(args['process'],validprocess) ; logging.error(msg) msg = header+"starting Propagate"+footer ; logging.info(msg)
raise IOError,msg dummy = Propagate(CycleInfo)
# Get name of the process requested msg = header+"starting SaveAndSubmit"+footer ; logging.info(msg)
dummy = SaveAndSubmit(CycleInfo)
process=args['process']
msg = "Cycle finished...exiting" ; logging.info(msg)
msg = 'Process %s starting, entered python from master shell'%process ; logging.debug(msg)
dummy = CleanUpCycle(CycleInfo)
if process == 'jobstart':
rcf = JobStart(opts,args)
if process == 'jobinput':
dummy = JobInput(args)
if process == 'sample':
dummy = ForwardRun(args,'forecast')
if process == 'invert':
dummy = Invert(args)
if process == 'propagate':
dummy = Propagate(args)
if process == 'resubmit':
dummy = SaveAndSubmit(args)
if process == 'all':
args['jobrcfilename'] = "jb.%s.rc"%(os.getpid(),)
msg = header+"starting JobStart"+footer ; logging.info(msg)
rcf = JobStart(opts,args)
msg = header+"starting JobInput"+footer ; logging.info(msg)
dummy = JobInput(args)
msg = header+"starting ForwardRun"+footer ; logging.info(msg)
dummy = ForwardRun(args,'forecast')
msg = header+"starting Invert"+footer ; logging.info(msg)
dummy = Invert(args)
msg = header+"starting Propagate"+footer ; logging.info(msg)
dummy = Propagate(args)
msg = header+"starting SaveAndSubmit"+footer ; logging.info(msg)
dummy = SaveAndSubmit(args)
msg = "Cycle finished...exiting" ; logging.info(msg)
# move log file to rundir/jobs
jobdir = os.path.join(rcf['dir.da_run'],"jobs")
joblogfile = os.path.join(jobdir,logfile)
dummy = shutil.move(logfile,joblogfile)
msg = "....Moved %s to %s"%(logfile,joblogfile) ; logging.debug(msg)
# move rc file to rundir/jobs
jobrcfile = os.path.join(jobdir,args["jobrcfilename"] )
dummy = shutil.move(args["jobrcfilename"],jobrcfile )
msg = "....Moved %s to %s"%(args['jobrcfilename'],jobrcfile) ; logging.debug(msg)
# cat TM5 output and rc-file to the job file output
tm5jobfile = os.path.join(jobdir,"tm5.%s"%(args['logfile']) )
if os.path.exists(tm5jobfile):
msg = "....Concatenating %s to %s"%(tm5jobfile,joblogfile) ; logging.debug(msg)
f = open(joblogfile,'a')
dummy = f.write(open(tm5jobfile,'r').read())
dummy = f.close()
if os.path.exists(jobrcfile):
msg = "....Concatenating %s to %s"%(jobrcfile,joblogfile) ; logging.debug(msg)
f = open(joblogfile,'a')
dummy = f.write(open(jobrcfile,'r').read())
dummy = f.close()
msg = "The complete log file is now at: %s"%(joblogfile) ; logging.info(msg)
msg = 'Process %s done, returning from python to master shell'%process ; logging.debug(msg)
sys.exit(0) sys.exit(0)
...@@ -53,7 +53,7 @@ class TM5(): ...@@ -53,7 +53,7 @@ class TM5():
[]> tm.WriteRunRc() []> tm.WriteRunRc()
[]> tm.Run() []> tm.Run()
To use this class inside a data assimilation cycle, a stand-alone method "PrepareExe()" is included which modifies the TM5 To use this class inside a data assimilation cycle, a stand-alone method "Initialize()" is included which modifies the TM5
settings according to an external dictionary of values to overwrite, and then runs the TM5 model. settings according to an external dictionary of values to overwrite, and then runs the TM5 model.
...@@ -233,7 +233,7 @@ class TM5(): ...@@ -233,7 +233,7 @@ class TM5():
self.Status = 'Success' self.Status = 'Success'
else: else:
logging.error('Error in model executable return code: %s ' % code) logging.error('Error in model executable return code: %s ' % code)
logging.info('Inspect [%s] to find output from model executable ' % modellogfilename) logging.info('Inspect [%s] to find output from model executable ' % self.ModelLogFilename)
self.Status = 'Failed' self.Status = 'Failed'
raise OSError raise OSError
...@@ -281,7 +281,7 @@ class TM5(): ...@@ -281,7 +281,7 @@ class TM5():
def PrepareExe(rc_da_shell): def Initialize(rc_da_shell):
""" """
Prepare a forward model TM5 run, this consists of: Prepare a forward model TM5 run, this consists of:
...@@ -293,9 +293,7 @@ def PrepareExe(rc_da_shell): ...@@ -293,9 +293,7 @@ def PrepareExe(rc_da_shell):
""" """
from tools_da import CreateLinks, CreateDirs, ParseTimes, StartLogger from tools_da import CreateLinks, CreateDirs
StartLogger()
# Make an instance of the TM5 class, supply it with a valid rc-file name # Make an instance of the TM5 class, supply it with a valid rc-file name
...@@ -304,22 +302,23 @@ def PrepareExe(rc_da_shell): ...@@ -304,22 +302,23 @@ def PrepareExe(rc_da_shell):
# Create a link from TM5 to the rundirectory of the das system # Create a link from TM5 to the rundirectory of the das system
sourcedir = Tm5Model.tm_settings['rundir'] sourcedir = Tm5Model.tm_settings['rundir']
targetdir = os.path.join(rc_da_shell['dir.exec']) targetdir = os.path.join(rc_da_shell['dir.exec'],'tm5')
CreateLinks(sourcedir,targetdir) CreateLinks(sourcedir,targetdir)
# Extract time information from the das system rc_da_shell['dir.exec.tm5'] = targetdir
ParseTimes(rc_da_shell)
# Write a modified TM5 model rc-file in which run/break times are defined by our da system # Write a modified TM5 model rc-file in which run/break times are defined by our da system
NewItems = { NewItems = {
'time.start': rc_da_shell['startdate'] , 'time.start' : rc_da_shell['startdate'] ,
'time.final' : rc_da_shell['enddate'] , 'time.final' : rc_da_shell['sample.enddate'] ,
'rundir' : rc_da_shell['dir.exec'] , 'rundir' : rc_da_shell['dir.exec.tm5'] ,
'savedir' : rc_da_shell['dir.save'] , 'outputdir' : rc_da_shell['dir.output'] ,
'outputdir': rc_da_shell['dir.output'] 'savedir' : rc_da_shell['dir.save'] ,
'das.input.dir' : rc_da_shell['dir.input']
} }
if rc_da_shell['time.restart'] == True: NewItems['istart'] = 3
Tm5Model.ModifyRC(NewItems) Tm5Model.ModifyRC(NewItems)
...@@ -329,7 +328,7 @@ def PrepareExe(rc_da_shell): ...@@ -329,7 +328,7 @@ def PrepareExe(rc_da_shell):
# Copy the pre-compiled MPI wrapper to the execution directory # Copy the pre-compiled MPI wrapper to the execution directory
targetdir = os.path.join(rc_da_shell['dir.exec']) targetdir = os.path.join(rc_da_shell['dir.exec.tm5'])
if not os.path.exists(mpi_shell_file): if not os.path.exists(mpi_shell_file):
msg = "Cannot find the mpi_shell wrapper needed for completion (%s)"% mpi_shell_file ; logging.error(msg) msg = "Cannot find the mpi_shell wrapper needed for completion (%s)"% mpi_shell_file ; logging.error(msg)
...@@ -362,7 +361,7 @@ if __name__ == "__main__": ...@@ -362,7 +361,7 @@ if __name__ == "__main__":
#dasrc['dir.output']=os.path.join(dasrc['dir.da_run'],'output') #dasrc['dir.output']=os.path.join(dasrc['dir.da_run'],'output')
#dasrc['dir.exec']=os.path.join(dasrc['dir.da_run'],'exec') #dasrc['dir.exec']=os.path.join(dasrc['dir.da_run'],'exec')
#tm = PrepareExe(dasrc) #tm = Initialize(dasrc)
#tm.Run() #tm.Run()
#tm.SaveData() #tm.SaveData()
......
...@@ -18,22 +18,7 @@ import shutil ...@@ -18,22 +18,7 @@ import shutil
import rc import rc
import datetime import datetime
needed_rc_da_items=[ def StartLogger(logfile='jb.%s.log'%os.getpid()):
'time.start',
'time.finish',
'time.nlag',
'time.cycle',
'dir.da_run',
'forecast.model',
'forecast.model.rc',
'da.system']
helptext=\
"""
HELP!!!
"""
def StartLogger(logfile='logfile.log'):
""" start the logging of messages to screen and to file""" """ start the logging of messages to screen and to file"""
# start the logging basic configuration by setting up a log file # start the logging basic configuration by setting up a log file
...@@ -110,22 +95,20 @@ def ParseOptions(): ...@@ -110,22 +95,20 @@ def ParseOptions():
return opts, arguments return opts, arguments
def ValidateRC(rcfile,needed_items): def ValidateOptsArgs(opts,args):
""" validate the contents of an rc-file given a dictionary of required keys """ """ Validate the options and arguments passed from the command line before starting the cycle """
for k,v in rcfile.iteritems(): if not args.has_key("rc"):
if v == 'True' : rcfile[k] = True msg = "There is no rc-file specified on the command line. Please use rc=yourfile.rc" ; logging.error(msg)
if v == 'False': rcfile[k] = False raise IOError,msg
if 'date' in k : rcfile[k] = datetime.datetime.strptime(v,'%Y-%m-%d %H:%M:%S') elif not os.path.exists(args['rc']):
msg = "The specified rc-file (%s) does not exist " % args['rc'] ; logging.error(msg)
raise IOError,msg
for key in needed_items: args['jobrcfilename'] = "jb.%s.rc"%(os.getpid(),)
args['logfile'] = "jb.%s.log"%(os.getpid(),)
if not rcfile.has_key(key): return opts,args
status,msg = ( False,'Missing a required value in rc-file : %s' % key)
logging.error(msg)
raise IOError,msg
status,msg = ( True,'rc-file has been validated succesfully' ) ; logging.debug(msg)
def CreateDirs(dirname,forceclean=False): def CreateDirs(dirname,forceclean=False):
""" Create a directory and report success, only if non-existent """ """ Create a directory and report success, only if non-existent """
...@@ -164,7 +147,7 @@ def CreateLinks(sourcedir,targetdir): ...@@ -164,7 +147,7 @@ def CreateLinks(sourcedir,targetdir):
return None return None
def SetInterval(rc_da_shell,run='forecast'): def SetInterval(CycleInfo,run='forecast'):
""" Set the interval over which the observation operator will be run. There are two options: """ Set the interval over which the observation operator will be run. There are two options:
(1) forecast : the simulation runs from startdate to startdate + nlag*delta_time (1) forecast : the simulation runs from startdate to startdate + nlag*delta_time
...@@ -174,9 +157,9 @@ def SetInterval(rc_da_shell,run='forecast'): ...@@ -174,9 +157,9 @@ def SetInterval(rc_da_shell,run='forecast'):
if run not in ['forecast','advance']: if run not in ['forecast','advance']:
raise ValueError, "Unknown interval specified for run (%s)" % run raise ValueError, "Unknown interval specified for run (%s)" % run
nlag = int(rc_da_shell['time.nlag']) nlag = int(CycleInfo.da_settings['time.nlag'])
startdate = rc_da_shell['startdate'] startdate = CycleInfo.da_settings['startdate']
cyclelen = rc_da_shell['cyclelength'] cyclelen = CycleInfo.da_settings['cyclelength']
if run == 'forecast': if run == 'forecast':
...@@ -189,7 +172,7 @@ def SetInterval(rc_da_shell,run='forecast'): ...@@ -189,7 +172,7 @@ def SetInterval(rc_da_shell,run='forecast'):
enddate = AdvanceTime(startdate,cyclelen) enddate = AdvanceTime(startdate,cyclelen)
rc_da_shell['enddate'] = enddate CycleInfo.da_settings['sample.enddate'] = enddate
msg = "New simulation interval set : " ; logging.info(msg) msg = "New simulation interval set : " ; logging.info(msg)
msg = " start date : %s " % startdate.strftime('%F %H:%M') ; logging.info(msg) msg = " start date : %s " % startdate.strftime('%F %H:%M') ; logging.info(msg)
...@@ -216,48 +199,6 @@ def AdvanceTime(time_in,interval): ...@@ -216,48 +199,6 @@ def AdvanceTime(time_in,interval):
return time_out return time_out
def ParseTimes(rc_da_shell):
""" get time parameters from rc-file and parse into datetime objects for later use """
td = rc_da_shell['time.start']
ymd = map(int,[td[0:4],td[4:6],td[6:8],td[8:10]]) # creates a 6-digit integer yyyy,mm,dd,hh,mn,sec
startdate = datetime.datetime(*ymd) # from which we create a python datetime object
td = rc_da_shell['time.finish']
ymd = map(int,[td[0:4],td[4:6],td[6:8],td[8:10]]) # again
finaldate = datetime.datetime(*ymd) # again
if finaldate <= startdate:
msg = 'The start date (%s) is not greater than the end date (%s), please revise'%(startdate.strftime('%Y%M%d'),finaldate.strftime('%Y%M%d'))
logging.error(msg)
raise ValueError
#
cyclelength = rc_da_shell['time.cycle'] # get time step
# Determine end date
if cyclelength == 'infinite':
enddate = finaldate
else:
enddate = AdvanceTime(startdate,cyclelength)
#
if enddate > finaldate: # do not run beyon finaldate
enddate = finaldate
rc_da_shell['startdate'] = startdate
rc_da_shell['enddate'] = enddate
rc_da_shell['finaldate'] = finaldate
rc_da_shell['cyclelength'] = cyclelength
msg = "===============================================================" ; logging.info(msg)
msg = "Filter start date is %s" % startdate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
msg = "Filter end date is %s" % enddate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
msg = "Filter final date is %s" % finaldate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
msg =