diff --git a/src/Applications/LDAS_App/GEOSldas_LDAS.rc b/src/Applications/LDAS_App/GEOSldas_LDAS.rc index b70f3417..02d62f33 100644 --- a/src/Applications/LDAS_App/GEOSldas_LDAS.rc +++ b/src/Applications/LDAS_App/GEOSldas_LDAS.rc @@ -41,16 +41,16 @@ LSM_CHOICE: 1 # If only whitelist should be used, specify dummy valuessuch that: # MINLON > MAXLON and MINLAT > MAXLAT. # -# MINLON : -180. -# MAXLON : 180. -# MINLAT : -90. -# MAXLAT : 90. +# MINLON: -180. +# MAXLON: 180. +# MINLAT: -90. +# MAXLAT: 90. # # Specify path and filenames for blacklist and whitelist files: # (May leave blank.) # -# BLACK_FILE : '' -# WHITE_FILE : '' +# BLACK_FILE: '' +# WHITE_FILE: '' # ---- Surface meteorological forcing: Time step @@ -58,14 +58,14 @@ LSM_CHOICE: 1 # Should be set in the exeinp file where MET_PATH is defined # 3600 = default # -# FORCE_DTSTEP : 3600 +# FORCE_DTSTEP: 3600 # ---- Surface meteorological forcing: Horizonal interpolation # # 1 : bilinear interpolation (default) # 0 : nearest neighbor # -MET_HINTERP : 1 +MET_HINTERP: 1 # ---- Specify if running model only or data assimilation @@ -73,7 +73,7 @@ MET_HINTERP : 1 # NO : model only (DEFAULT; with --runmodel option) # YES : assimilation (without --runmodel option) # -LAND_ASSIM : NO +LAND_ASSIM: NO # ---- Perturbations: On/off @@ -83,11 +83,11 @@ LAND_ASSIM : NO # 0 : No perturbactions. # 1 : With perturbations. # -PERTURBATIONS : 0 +PERTURBATIONS: 0 # ---- Perturbations: ID of first ensemble member # -FIRST_ENS_ID : 0 +FIRST_ENS_ID: 0 # ---- Path to special namelist input files @@ -98,7 +98,7 @@ FIRST_ENS_ID : 0 # LDASsa_SPECIAL_inputs_ensprop.nml # LDASsa_SPECIAL_inputs_catbias.nml # -# NML_INPUT_PATH : '' +# NML_INPUT_PATH: '' # ---- Microwave Radiative Transfer Model (mwRTM) parameter file name (nc4 format) used for Tb assimilation @@ -106,7 +106,7 @@ FIRST_ENS_ID : 0 # This file can be converted from binary with the program mwrtm_bin2nc4.x. # If empty or commented out, GEOSldas will search the restart directory. # -# MWRTM_FILE : '' +# MWRTM_FILE: '' # ---- Job segments: Length @@ -115,7 +115,7 @@ FIRST_ENS_ID : 0 # Default is the entire simulation period (END_DATE minus BEG_DATE). # Format: yyyymmdd hhmmss # -# JOB_SGMT : 00000100 000000 +# JOB_SGMT: 00000100 000000 # ---- Job segments: Number # @@ -124,31 +124,34 @@ FIRST_ENS_ID : 0 # Low values for NUM_SGMT are recommended for run-time and storage efficiency. # Default is 1. # -# NUM_SGMT : 1 +# NUM_SGMT: 1 # ---- Output: Write log file (YES/NO)? # -LDAS_logit : YES +LDAS_logit: YES # ---- Output: HISTORY definition of model diagnostics # # User-defined path and filename of output (HISTORY) specification file. # If empty, ldas_setup will generate a default HISTORY.rc file. # -# HISTRC_FILE : '' +# HISTRC_FILE: '' -# ---- Write only monthly output? +# ---- Concatenate sub-daily nc4 files into daily nc4 files and write monthly-mean output? # -# Monthly files can be created from daily files. -# Accurate monthly averages require setting "ref_time" in HISTORY.rc to "000000" +# Optional post-processing of model diagnostics output into bundled daily files and monthly means. +# Reduces the file count and (optionally) the output volume. # -# 0 : Output bundled into daily files per HISTORY specifications (default). -# 1 : Monthly files will be created. Daily files will *not* be deleted. -# 2 : Monthly files will be created and daily files will be deleted automatically. +# Accurate monthly-means of time-average Collections require setting "ref_time" to "000000" in HISTRC_FILE! # -# MONTHLY_OUTPUT : 0 - +# 0 : No post-processing (default). +# 1 : For complete days, concatenate (bundle) sub-daily nc4 files, if any, into daily nc4 files. +# For complete months, write monthly-mean nc4 files. +# 2 : As in 1, but delete daily nc4 files. +# +# POSTPROC_HIST: 0 + # ---- Name of file containing Surface GridComp resource parameters # @@ -161,12 +164,12 @@ SURFRC: LDAS.rc # ---- No dycore for offline # -DYCORE : none +DYCORE: none # ---- Only one surface level # -LM : 1 +LM: 1 # ---- For MAPL_RestartOptional # -MAPL_ENABLE_BOOTSTRAP : YES +MAPL_ENABLE_BOOTSTRAP: YES diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 9e8b5a5b..0ddf401d 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -32,18 +32,18 @@ class LDASsetup: # Required exe input fields # These fields are needed to pre-compute exp dir structure # ------ - rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_ENSEMBLE', + rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH'] - rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_ENSEMBLE', + rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH'] - # These keywords are excluded from LDAS.rc + # These keywords are excluded from LDAS.rc (i.e., only needed in pre- or post-processing) self.NoneLDASrcKeys=['EXP_ID', 'EXP_DOMAIN', 'BEG_DATE', 'END_DATE','RESTART','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','BCS_PATH','TILING_FILE','GRN_FILE','LAI_FILE','NIRDF_FILE', 'VISDF_FILE','CATCH_DEF_FILE','NDVI_FILE', - 'NML_INPUT_PATH','HISTRC_FILE','RST_FROM_GLOBAL','JOB_SGMT','NUM_SGMT','MONTHLY_OUTPUT', + 'NML_INPUT_PATH','HISTRC_FILE','RST_FROM_GLOBAL','JOB_SGMT','NUM_SGMT','POSTPROC_HIST', 'MINLON','MAXLON','MINLAT','MAXLAT','BLACK_FILE','WHITE_FILE','MWRTM_FILE'] @@ -62,7 +62,7 @@ class LDASsetup: if 'exeinp' in cmdLineArgs: # sample sub-command # by construction, we can have - # either: {'exeinp': False, 'batinp': 'lasgh'} + # either: {'exeinp': False, 'batinp': 'lasgh'} <-- 'lasgh'??? # or: {'exeinp': True, 'batinp': None} if cmdLineArgs['exeinp']: _printExeInputKeys(rqdExeInpKeys) @@ -84,7 +84,6 @@ class LDASsetup: self.runmodel = cmdLineArgs['runmodel'] self.daysperjob = cmdLineArgs['daysperjob'] self.monthsperjob = cmdLineArgs['monthsperjob'] - #self.ForceReuseDir = cmdLineArgs['ForceReuseDir'] self.rqdExeInp = OrderedDict() self.rqdRmInp = OrderedDict() self.optRmInp = OrderedDict() @@ -103,7 +102,7 @@ class LDASsetup: self.has_ldassa_pert = False self.nSegments = 1 # ------ - # Read exe input file which is required to setup the dir + # Read exe input file which is required to set up the dir # ------ self.rqdExeInp = self._parseInputFile(cmdLineArgs['exeinpfile']) # verifing the required input @@ -134,8 +133,8 @@ class LDASsetup: _printdict(self.rqdExeInp) # nens is an integer and =1 for model run - self.nens = int(self.rqdExeInp['NUM_ENSEMBLE']) # fail if Nens's val is not int - assert self.nens>0, 'NUM_ENSEMBLE [%d] <= 0' % self.nens + self.nens = int(self.rqdExeInp['NUM_LDAS_ENSEMBLE']) # fail if Nens's val is not int + assert self.nens>0, 'NUM_LDAS_ENSEMBLE [%d] <= 0' % self.nens _mydir = self.exphome + '/' + self.rqdExeInp['EXP_ID'] assert not os.path.isdir(_mydir), 'Dir [%s] already exists!' % _mydir _mydir = None @@ -167,7 +166,7 @@ class LDASsetup: ) if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) == 0 : - # print "Starting date is forced to January 1st if there is no restart file" + print "No restart file (cold restart): Forcing start date to January 1, 0z" year = self.begDates[0].year self.begDates[0]=datetime(year =year,month=1,day =1,hour =0, minute= 0,second= 0) @@ -283,12 +282,8 @@ class LDASsetup: else : self.catch = 'catchcn' - if 'MONTHLY_OUTPUT' not in self.rqdExeInp: - self.rqdExeInp['MONTHLY_OUTPUT'] = 0 - - #if int(self.rqdExeInp['MONTHLY_OUTPUT']) > 0: - # assert self.begDates[0].day == 1 and self.begDates[0].hour == 0 and self.begDates[0].minute == 0 and self.begDates[0].second == 0, "monthly output should start from day 1 and 0Z" - # assert self.endDates[0].day == 1 and self.endDates[0].hour == 0 and self.endDates[0].minute == 0 and self.endDates[0].second == 0, "monthly output should end at day 1 and 0Z" + if 'POSTPROC_HIST' not in self.rqdExeInp: + self.rqdExeInp['POSTPROC_HIST'] = 0 if 'RUN_IRRIG' not in self.rqdExeInp: self.rqdExeInp['RUN_IRRIG'] = 0 @@ -443,101 +438,6 @@ class LDASsetup: tmp_expid = None tmp_expdir = None - # ------ - # If daysperjob>0, split duration of - # start/end_times are now lists of len > 1 - # ------ - # wj notes: disable daysperjob -# self.daysperjob = 0 -# if self.daysperjob: -# # shorthands -# _dpj = self.daysperjob -# _start = self.begDates[0] -# _end = self.endDates[0] -# assert _dpj>0, 'daysperjob = %d' % _dpj -# # total number of days for the given job -# nDays = (_end - _start).days -# assert nDays>_dpj, \ -# 'Days per job [%d] >= Duration [%d days]' %\ -# (_dpj, nDays) -# # number of job segments -# q = nDays/_dpj -# r = nDays%_dpj -# if r>0: -# nSegments = q+1 -# else: -# nSegments = q -# # lists of start times, end times -# _start_list = list() -# _end_list = list() -# for iseg in xrange(nSegments): -# _start_list.append(_start+timedelta(days=iseg*_dpj)) -# for iseg in xrange(nSegments-1): -# _end_list.append(_start_list[iseg+1]) -# _end_list.append(_end) -# -# #update beg dates and end dates -# self.begDates = _start_list -# self.endDates = _end_list -# self.job_sgmt = list() -# for iseg in xrange(nSegments): -# self.job_sgmt.append("JOB_SGMT: 000000%02d 000000"%(self.endDates[iseg]-self.begDates[iseg]).days) -# -# # print, if requested -# if self.verbose: -# print '\nn start end' -# for iseg in xrange(nSegments): -# print iseg, ':', _start_list[iseg], '-', _end_list[iseg] -# -# # wj notes: disable monthsperjob -# self.monthsperjob = 0 -# if self.monthsperjob: -# # shorthands -# _mpj = self.monthsperjob -# assert _mpj>0, 'monthsperjob = %d' % _mpj -# _start = self.begDates[0] -# _end = self.endDates[0] -# # for this option the start/end dates have to be -# # 0z on the first of the month -# assert (_start.day==1 and _start.hour==0 and -# _start.minute==0 and _start.second==0 -# ), 'invalid start_time: %s for --monthsperjob' % \ -# _start.strftime('%Y-%m-%d-%H-%M-%S') -# assert (_end.day==1 and _end.hour==0 and -# _end.minute==0 and _end.second==0 -# ), 'invalid end_time: %s for --monthsperjob' % \ -# _end.strftime('%Y-%m-%d-%H-%M-%S') -# _start_list = list() -# _end_list = list() -# for dt in rrule.rrule(rrule.MONTHLY, interval=_mpj, dtstart=_start, until=_end): -# seg_start = dt -# seg_end = dt+relativedelta(months=_mpj) -# if seg_end>_end: -# seg_end = _end -# if(seg_start>=seg_end) : -# break -# _start_list.append(seg_start) -# _end_list.append(seg_end) -# -# #update beg dates and end dates -# -# self.begDates = _start_list -# self.endDates = _end_list -# self.job_sgmt =list() -# for iseg in xrange(len(_start_list)): -# months = 0 -# dt = relativedelta(months=+1) -# d = self.begDates[iseg] -# while d "' in line: continue - # get "GEOSldas=>" defalut in GEOS_LandGrid.rc + # get "GEOSldas=>" default in GEOS_LandGrid.rc if 'GEOSldas=>' in line: line = line.split('GEOSldas=>')[1] # handle comments @@ -713,7 +613,7 @@ class LDASsetup: if 'SURFLAY' in self.rqdExeInp : dzsf = self.rqdExeInp['SURFLAY'] - # These are dummy values for cold restart: + # These are dummy values for *cold* restart: wemin_in = '13' # WEmin input/output for scale_catch(cn), wemin_out = '13' # if 'WEMIN_IN' in self.rqdExeInp : @@ -807,7 +707,7 @@ class LDASsetup: rstdomain = self.rqdExeInp['RESTART_DOMAIN'] rstpath0 = self.rqdExeInp['RESTART_PATH'] - # just copy the landassim pert seed if it exist + # just copy the landassim pert seed if it exists for iens in xrange(self.nens) : _ensdir = self.ensdirs[iens] _ensid = self.ensids[iens] @@ -1072,7 +972,7 @@ class LDASsetup: #sp.call(cmd) for line in fileinput.input(tmprcfile,inplace=True): print line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID']) - # just copy en emty ExtData.rc + # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : shutil.copy2(rcfile, self.rundir+'/'+shortfile) @@ -1098,7 +998,7 @@ class LDASsetup: for key,val in default_surfrcInp.iteritems() : ldasrcInp[key] = val - # ldas default, may overiwrite land default + # ldas default, may overwrite land default default_ldasrcInp = self._parseInputFile(rcfile) for key,val in default_ldasrcInp.iteritems() : ldasrcInp[key] = val @@ -1192,7 +1092,7 @@ class LDASsetup: # write LDAS.rc fout =open(self.rundir+'/'+shortfile,'w') - ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') + # ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') for key,val in optinxny.iteritems(): keyn=(key+":").ljust(36) fout.write(keyn+str(val)+'\n') @@ -1216,7 +1116,6 @@ class LDASsetup: _rm_name = self.rqdRmInp['rm_name'] expid = self.rqdExeInp['EXP_ID'] - #expdomain = self.rqdExeInp['EXP_DOMAIN'] if _rm_name=='SLURM': directives = '' # REQUIRED directives account/time/ntasks @@ -1378,18 +1277,16 @@ class LDASsetup: fout.write(line.replace('MY_EXPID',self.rqdExeInp['EXP_ID'])) elif 'MY_EXPDOMAIN' in line : fout.write(line.replace('MY_EXPDOMAIN',self.rqdExeInp['EXP_DOMAIN'])) - #elif 'MY_ESMADIR' in line : - # fout.write(line.replace('MY_ESMADIR',self.blddir)) elif 'MY_ENSEMBLE' in line : - fout.write(line.replace('MY_ENSEMBLE',str(self.rqdExeInp['NUM_ENSEMBLE']))) + fout.write(line.replace('MY_ENSEMBLE',str(self.rqdExeInp['NUM_LDAS_ENSEMBLE']))) elif 'MY_LOGFILE' in line : fout.write(line.replace('MY_LOGFILE',my_logfile)) elif 'MY_ERRFILE' in line : fout.write(line.replace('MY_ERRFILE',my_errfile)) elif 'MY_MODEL' in line : fout.write(line.replace('MY_MODEL',self.catch)) - elif 'MY_MONTHLY' in line : - fout.write(line.replace('MY_MONTHLY',str(self.rqdExeInp['MONTHLY_OUTPUT']))) + elif 'MY_POSTPROC_HIST' in line : + fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) @@ -1430,11 +1327,11 @@ def _printExeInputKeys(rqdExeInpKeys): print '# #' print '############################################################' print - print 'EXP_ID :' - print 'EXP_DOMAIN :' - print 'NUM_ENSEMBLE :' - print 'BEG_DATE :' - print 'END_DATE :' + print 'EXP_ID:' + print 'EXP_DOMAIN:' + print 'NUM_LDAS_ENSEMBLE:' + print 'BEG_DATE:' + print 'END_DATE:' print print '############################################################' @@ -1503,10 +1400,10 @@ def _printExeInputKeys(rqdExeInpKeys): print '############################################################' print - print 'RESTART :' - print '#RESTART_ID :' - print '#RESTART_PATH :' - print '#RESTART_DOMAIN :' + print 'RESTART:' + print '#RESTART_ID:' + print '#RESTART_PATH:' + print '#RESTART_DOMAIN:' print print '############################################################' @@ -1518,9 +1415,9 @@ def _printExeInputKeys(rqdExeInpKeys): print '############################################################' print - print 'MET_TAG :' - print 'MET_PATH :' - print 'FORCE_DTSTEP :' + print 'MET_TAG:' + print 'MET_PATH:' + print 'FORCE_DTSTEP:' print print '############################################################' @@ -1531,7 +1428,7 @@ def _printExeInputKeys(rqdExeInpKeys): print '# #' print '############################################################' print - print 'BCS_PATH :' + print 'BCS_PATH:' print _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory @@ -1652,11 +1549,6 @@ def parseCmdLine(): help='replace the account in batinpfile)', type=str, default='None' ) - #p_setup.add_argument( - # '--ForceReuseDir', - # help='force re-use existing exp dir', - # action='store_true', - # ) spltgrp = p_setup.add_mutually_exclusive_group() spltgrp.add_argument( '--daysperjob', diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index b8f4595c..07748581 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -41,12 +41,12 @@ setenv RUN_CMD "$GEOSBIN/esma_mpirun -np " # Experiment Specific Environment Variables ####################################################################### -setenv HOMDIR $EXPDIR/run/ -setenv SCRDIR $EXPDIR/scratch -setenv MODEL MY_MODEL -@ NENS = MY_ENSEMBLE -setenv MYNAME `finger $USER | cut -d: -f3 | head -1` -setenv NODAILIES MY_MONTHLY +setenv HOMDIR $EXPDIR/run/ +setenv SCRDIR $EXPDIR/scratch +setenv MODEL MY_MODEL +@ NENS = MY_ENSEMBLE +setenv MYNAME `finger $USER | cut -d: -f3 | head -1` +setenv POSTPROC_HIST MY_POSTPROC_HIST # # DEBUGGER : 0 -- no debugger @@ -308,7 +308,34 @@ while ( $counter <= ${NUM_SGMT} ) ####################################################################### - # Move HISTORY Files to cat/ens Directory + # Move Legacy LDASsa Files to ana/ens_avg Directory + ####################################################################### + + # must be done before moving HISTORY files + + set ObsFcses = `ls *.ldas_ObsFcstAna.*.bin` + foreach obsfcs ( $ObsFcses ) + set ThisTime = `echo $obsfcs | rev | cut -d'.' -f2 | rev` + set TY = `echo $ThisTime | cut -c1-4` + set TM = `echo $ThisTime | cut -c5-6` + set THISDIR = $EXPDIR/output/$EXPDOMAIN/ana/ens_avg/Y${TY}/M${TM}/ + if (! -e $THISDIR ) mkdir -p $THISDIR + /bin/mv $obsfcs ${THISDIR}$obsfcs + end + + set smapL4s = `ls *.ldas_tile_inst_smapL4SMaup.*.bin` + foreach smapl4 ( $smapL4s ) + set ThisTime = `echo $smapl4 | rev | cut -d'.' -f2 | rev` + set TY = `echo $ThisTime | cut -c1-4` + set TM = `echo $ThisTime | cut -c5-6` + set THISDIR = $EXPDIR/output/$EXPDOMAIN/ana/ens_avg/Y${TY}/M${TM}/ + if (! -e $THISDIR ) mkdir -p $THISDIR + /bin/mv $smapl4 ${THISDIR}$smapl4 + end + + + ####################################################################### + # Move HISTORY Files to cat/ens Directory ####################################################################### set outfiles = `ls $EXPID.*[bin,nc4]` @@ -367,11 +394,12 @@ while ( $counter <= ${NUM_SGMT} ) done: ####################################################################### - # (1) Concatenating Sub-daily Files to Daily Files - # (2) Write monthly means + # Post-Process model diagnostic output + # (1) Concatenate sub-daily files to daily files + # (2) Write monthly means ####################################################################### - if ($NODAILIES > 0) then + if ($POSTPROC_HIST > 0) then set PWD = `pwd` @@ -405,7 +433,20 @@ while ( $counter <= ${NUM_SGMT} ) @ day++ set time_steps = `ls -1 $EXPID.$ThisCol.${YYYY}${MM}${DD}_* | rev | cut -d'.' -f2 | rev` set LEN_SUB = `echo $#time_steps` + + # no file or just one file? nothing to concatenate, move on to the next collection if ($LEN_SUB <= 1) continue + + # check if day is complete (get HISTORY time step from first two files) + set hour1 = `echo $time_steps[1] | cut -c10-11` + set min1 = `echo $time_steps[1] | cut -c12-13` + set hour2 = `echo $time_steps[2] | cut -c10-11` + set min2 = `echo $time_steps[2] | cut -c12-13` + @ dt_hist = ($hour2 - $hour1) * 60 + ($min2 - $min1) + @ N_per_day = (24 * 60) / $dt_hist + # not enough sub-daily files? move on to the next collection + if($LEN_SUB < $N_per_day) continue + set tstep2 = \"`echo $time_steps | sed 's/\ /\","/g'`\" # ---------------------------------------------------------------------------- @@ -434,45 +475,67 @@ EOF ncks -4 -h -v time_stamp timestamp.nc4 -A ${EXPID}.${ThisCol}.$YYYY$MM$DD.nc4 /bin/rm timestamp.cdl /bin/rm timestamp.nc4 - /bin/rm $EXPID.${ThisCol}.${YYYY}${MM}${DD}_*.nc4 - + # rudimentary check for desired nc4 file; if ok, delete sub-daily files + if ( -f ${EXPID}.${ThisCol}.$YYYY$MM$DD.nc4 ) then + if ( ! -z ${EXPID}.${ThisCol}.$YYYY$MM$DD.nc4 ) then + /bin/rm $EXPID.${ThisCol}.${YYYY}${MM}${DD}_*.nc4 + endif + endif end # concatenate for each day - - set time_steps = `ls -1 $EXPID.$ThisCol.${YYYY}${MM}* | rev | cut -d'.' -f2 | rev` - set tstep2 = \"`echo $time_steps | sed 's/\ /\","/g'`\" - set LEN = `echo $#time_steps` - # no file? move on - if ($LEN == 0) continue - - set dayl = `echo $time_steps[$LEN] | cut -c1-8` - set day1 = `echo $time_steps[1] | cut -c1-8` - @ NAVAIL = ($dayl - $day1) + 1 - - # not enough days? move on to the next collection - if($NAVAIL != $NDAYS) continue - - # create the monly average - ncra -h $EXPID.$ThisCol.${YYYY}${MM}??.nc4 ${EXPID}.${ThisCol}.monthly.$YYYY$MM.nc4 + # write monthly mean file and (optionally) remove daily files + # ------------------------------------------------------------------ + + # NOTE: Collections written with daily frequency ("tavg24" and "inst24") have not + # been concatenated into daily files. There are two possibilities for the + # time stamps of files to be averaged: + # *.YYYYMMDD.* daily files from concatenation of sub-daily files + # *.YYYYMMDD_HHMM.* daily (avg or inst) files written directly by HISTORY.rc + + set time_steps = `ls -1 $EXPID.$ThisCol.${YYYY}${MM}??.* | rev | cut -d'.' -f2 | rev` + set time_steps_ = `ls -1 $EXPID.$ThisCol.${YYYY}${MM}??_* | rev | cut -d'.' -f2 | cut -d'_' -f2 | rev` + set LEN = `echo $#time_steps` + set LEN_ = `echo $#time_steps_` + + # check if month is complete + if ($LEN != 0) then + set dayl = `echo $time_steps[$LEN] | cut -c1-8` + set day1 = `echo $time_steps[1] | cut -c1-8` + @ NAVAIL = ($dayl - $day1) + 1 + else if( $LEN_ !=0 ) then + set dayl = `echo $time_steps_[$LEN] | cut -c1-8` + set day1 = `echo $time_steps_[1] | cut -c1-8` + @ NAVAIL = ($dayl - $day1) + 1 + else + @ NAVAIL = 0 + endif + + # not enough days for monthly mean? move on to the next collection + if($NAVAIL != $NDAYS) continue + + # create monthly-mean nc4 file + ncra -h $EXPID.$ThisCol.${YYYY}${MM}*.nc4 ${EXPID}.${ThisCol}.monthly.$YYYY$MM.nc4 - # don't want a daily? delete the daily and sub-dailies and continue - # - if($NODAILIES == 2) then - /bin/rm $EXPID.${ThisCol}.${YYYY}${MM}* + if($POSTPROC_HIST == 2) then + # rudimentary check for desired nc4 file; if ok, delete daily files + if ( -f ${EXPID}.${ThisCol}.monthly.$YYYY$MM.nc4 ) then + if ( ! -z ${EXPID}.${ThisCol}.monthly.$YYYY$MM.nc4 ) then + /bin/rm $EXPID.${ThisCol}.${YYYY}${MM}* + endif + endif continue endif end # each collection end # each month cd $PWD - endif # dailies > 0 + endif # POSTPROC_HIST > 0 ####################################################################### # Rename Final Checkpoints => Restarts for Next Segment and Archive # Note: cap_restart contains the current NYMD and NHMS ####################################################################### - set edate = e`cat cap_restart | cut -c1-8`_`cat cap_restart | cut -c10-11`z set eYEAR = `cat cap_restart | cut -c1-4` set eMON = `cat cap_restart | cut -c5-6` set eDAY = `cat cap_restart | cut -c7-8` @@ -558,45 +621,36 @@ EOF set rstfiles2 = `ls landpert${ENSID}_internal_checkpoint.*` set rstfiles3 = `ls landassim_obspertrseed${ENSID}_checkpoint.*` - set NFILES = `echo $#rstfiles1` - if($NFILES > 0) then - foreach rfile ( $rstfiles1 ) - set ThisTime = `echo $rfile | rev | cut -d'.' -f2 | rev` - set TY = `echo $ThisTime | cut -c1-4` - set TM = `echo $ThisTime | cut -c5-6` - set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${TY}/M${TM}/ - if (! -e $THISDIR ) mkdir -p $THISDIR - /bin/mv $rfile ${THISDIR}${EXPID}.${MODEL}_internal_rst.${ThisTime}.nc4 - /usr/bin/gzip ${THISDIR}${EXPID}.${MODEL}_internal_rst.${ThisTime}.nc4 & - end - endif + foreach rfile ( $rstfiles1 ) + set ThisTime = `echo $rfile | rev | cut -d'.' -f2 | rev` + set TY = `echo $ThisTime | cut -c1-4` + set TM = `echo $ThisTime | cut -c5-6` + set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${TY}/M${TM}/ + if (! -e $THISDIR ) mkdir -p $THISDIR + /bin/mv $rfile ${THISDIR}${EXPID}.${MODEL}_internal_rst.${ThisTime}.nc4 + /usr/bin/gzip ${THISDIR}${EXPID}.${MODEL}_internal_rst.${ThisTime}.nc4 & + end - set NFILES = `echo $#rstfiles2` - if($NFILES > 0) then - foreach rfile ( $rstfiles2 ) - set ThisTime = `echo $rfile | rev | cut -d'.' -f2 | rev` - set TY = `echo $ThisTime | cut -c1-4` - set TM = `echo $ThisTime | cut -c5-6` - set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${TY}/M${TM}/ - if (! -e $THISDIR ) mkdir -p $THISDIR + foreach rfile ( $rstfiles2 ) + set ThisTime = `echo $rfile | rev | cut -d'.' -f2 | rev` + set TY = `echo $ThisTime | cut -c1-4` + set TM = `echo $ThisTime | cut -c5-6` + set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${TY}/M${TM}/ + if (! -e $THISDIR ) mkdir -p $THISDIR (ncks -4 -O -C -x -v lat,lon $rfile ${THISDIR}${EXPID}.landpert_internal_rst.${ThisTime}.nc4;\ /usr/bin/gzip ${THISDIR}${EXPID}.landpert_internal_rst.${ThisTime}.nc4; \ /bin/rm -f $rfile) & - end - endif + end - set NFILES = `echo $#rstfiles3` - if($NFILES > 0) then - foreach rfile ( $rstfiles3 ) - set ThisTime = `echo $rfile | rev | cut -d'.' -f2 | rev` - set TY = `echo $ThisTime | cut -c1-4` - set TM = `echo $ThisTime | cut -c5-6` - set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${TY}/M${TM}/ - if (! -e $THISDIR ) mkdir -p $THISDIR + foreach rfile ( $rstfiles3 ) + set ThisTime = `echo $rfile | rev | cut -d'.' -f2 | rev` + set TY = `echo $ThisTime | cut -c1-4` + set TM = `echo $ThisTime | cut -c5-6` + set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${TY}/M${TM}/ + if (! -e $THISDIR ) mkdir -p $THISDIR /bin/mv $rfile ${THISDIR}${EXPID}.landassim_obspertrseed_rst.${ThisTime}.nc4 - end - endif - + end + @ inens ++ end ## end of while ($inens < $NENS) wait @@ -625,7 +679,7 @@ EOF /bin/cp cap_restart $HOMDIR/cap_restart ####################################################################### - # Update Iteration Counter + # Update Iteration Counter ####################################################################### set enddate = `echo $END_DATE | cut -c1-8` @@ -641,7 +695,7 @@ EOF end ####################################################################### -# set next log and error file +# Set Next Log and Error Files ####################################################################### set logfile = $EXPDIR/output/$EXPDOMAIN/rc_out/Y${logYEAR}/M${logMON}/${EXPID}.ldas_log.${logYEAR}${logMON}${logDAY}_${logHour}${logMin}z.txt @@ -658,7 +712,7 @@ if(-f GEOSldas_err_txt) then endif ####################################################################### -# Re-Submit Job +# Re-Submit Job ####################################################################### if ( $rc == 0 ) then diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index d8f36efe..b0e7636b 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -31,8 +31,6 @@ module GEOS_LandAssimGridCompMod use LDAS_ensdrv_mpi, only: MPI_obs_param_type use LDAS_DateTimeMod,ONLY: date_time_type - use LDAS_ensdrv_functions, ONLY: & - get_io_filename use LDAS_ensdrv_Globals, only: logunit use LDAS_ConvertMod, ONLY: esmf2ldas diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 6ea5e3e3..4502a216 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -1555,11 +1555,8 @@ subroutine output_ObsFcstAna(date_time, work_path, exp_id, & endif ! write to file - fname = get_io_filename( work_path, exp_id, file_tag, date_time=date_time, & - dir_name=dir_name, ens_id=-1 ) - i = index(fname, '/', .true.) - - if( i >0) call Execute_command_line('/bin/mkdir -p '//fname(1:i)) + fname = get_io_filename( './', exp_id, file_tag, date_time=date_time, & + dir_name=dir_name, ens_id=-1, no_subdirs=.true. ) open( 10, file=fname, form='unformatted', action='write') @@ -2101,8 +2098,8 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & if (master_proc) then - fname = get_io_filename( work_path, exp_id, file_tag, & - date_time=date_time, dir_name=dir_name, ens_id=-1) + fname = get_io_filename( './', exp_id, file_tag, & + date_time=date_time, dir_name=dir_name, ens_id=-1, no_subdirs=.true.) if (option=='orig_obs') then diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 index 5bddad28..d539e241 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 @@ -20,7 +20,6 @@ module LDAS_ensdrv_Globals public :: nodata_generic public :: nodata_tolfrac_generic public :: nodata_tol_generic - public :: N_bits_shaved public :: logunit public :: logit public :: master_logit @@ -38,16 +37,6 @@ module LDAS_ensdrv_Globals real :: nodata_tol_generic = abs(nodata_generic*nodata_tolfrac_generic) - ! ---------------------------------------------------------------------- - ! - ! bit shaving for better gzip compression of output files: - ! - degrade least significant digits in floating point output - ! in return for better gzip compression rates; - ! - real*4 reserves 24 bits for Mantissa, the N_bits_shaved - ! least significant of these 24 bits will be altered) - - integer, parameter :: N_bits_shaved = 12 ! useful range: 0-12 (0=no shaving) - ! ---------------------------------------------------------------- ! ! log file @@ -88,8 +77,6 @@ subroutine echo_clsm_ensdrv_glob_param() write (logunit,*) write (logunit,*) 'nodata_tol_generic = ', nodata_tol_generic write (logunit,*) - write (logunit,*) 'N_bits_shaved = ', N_bits_shaved - write (logunit,*) write (logunit,*) 'logunit = ', logunit write (logunit,*) write (logunit,*) 'log_master_only = ', log_master_only diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 index 6d0b8caa..8495cd6b 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 @@ -33,9 +33,9 @@ module LDAS_ensdrv_functions ! ******************************************************************** character(300) function get_io_filename( io_path, exp_id, file_tag, & - date_time, dir_name, ens_id, option, file_ext ) + date_time, dir_name, ens_id, option, file_ext, no_subdirs ) - ! compose file name for input/output, create dir if needed + ! compose file name for input/output ! ! file name = io_path/dir_name/[ensXXXX]/Yyyyy/Mmm/ ! "exp_id"."file_tag".[ensXXXX.]YYYYMMDD_HHMMz"file_ext" @@ -56,37 +56,41 @@ character(300) function get_io_filename( io_path, exp_id, file_tag, & ! ! optional arguments: ! - ! date_time date and time info (must be present unless option=1) - ! option default=5 controls date/time directories and string - ! dir_name default='cat' what type of output (eg "rs/", "rc_out/", "ana/") - ! ens_id default='' (see note above) - ! file_ext default='.bin' file name extension + ! date_time date and time info (must be present unless option=1) + ! option default=5 controls date/time directories and string + ! dir_name default='cat' what type of output (eg "rs/", "rc_out/", "ana/") + ! ens_id default='' (see note above) + ! file_ext default='.bin' file name extension + ! no_subdirs default=.false. if .true., omit all sub-directories after "io_path" ! ! reichle, 2 Sep 2008 - overhaul for new dir and file name conventions - + ! reichle, 28 Apr 2020 - added optional "no_subdirs" to facilitate writing to ./scratch + implicit none - character(*) :: io_path - character(*) :: exp_id, file_tag ! (eg "catch_ldas_rst") + character(*) :: io_path + character(*) :: exp_id, file_tag ! (eg "catch_ldas_rst") type(date_time_type), optional :: date_time - integer, optional :: ens_id - integer, optional :: option + integer, optional :: ens_id + integer, optional :: option - character(*), optional :: dir_name ! default = 'cat' - character(*), optional :: file_ext ! default = '.bin' + character(*), optional :: dir_name ! default = 'cat' + character(*), optional :: file_ext ! default = '.bin' + + logical, optional :: no_subdirs ! default = .false. ! locals integer :: tmp_option character(300) :: tmp_string - character(300) :: tmp_string2 character( 40) :: tmp_dir_name, tmp_file_ext, date_time_string character( 8) :: ens_id_string character( 4) :: YYYY, MMDD, HHMM, tmpstring4 character( 2) :: PP + logical :: tmp_no_subdirs ! -------------------------------------------------------- ! @@ -109,6 +113,12 @@ character(300) function get_io_filename( io_path, exp_id, file_tag, & else tmp_file_ext = '.bin' end if + + if (present(no_subdirs)) then + tmp_no_subdirs = no_subdirs + else + tmp_no_subdirs = .false. + end if ! create date/time strings @@ -179,12 +189,19 @@ character(300) function get_io_filename( io_path, exp_id, file_tag, & end if ! compose output path - tmp_string = trim(io_path) // '/' // trim(tmp_dir_name) // '/' // & - trim(ens_id_string(2:8)) // '/' - if (tmp_option>1) & - tmp_string = trim(tmp_string) // '/Y'// YYYY // '/M'//MMDD(1:2) // '/' + tmp_string = trim(io_path) // '/' + if (.not. tmp_no_subdirs) then + + tmp_string = trim(tmp_string) // trim(tmp_dir_name) // '/' // & + trim(ens_id_string(2:8)) // '/' + + if (tmp_option>1) & + tmp_string = trim(tmp_string) // '/Y'// YYYY // '/M'//MMDD(1:2) // '/' + + end if + ! append file name to path get_io_filename = trim(tmp_string) // trim(exp_id) // &