From 888cca4cf3bc2ddda656884820e81639217b6868 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Fri, 25 Apr 2025 10:52:49 -0400 Subject: [PATCH 01/36] add setting defaults and more commdline options for ladas modified: ldas_setup --- GEOSldas_App/ldas_setup | 82 +++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index aeb152d4..85520fb7 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -40,8 +40,7 @@ class LDASsetup: 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', - 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] - + 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] # 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', @@ -90,6 +89,9 @@ class LDASsetup: self.exphome = os.path.abspath(exphome_) self.nymdb = cmdLineArgs['nymdb'] self.nhmsb = cmdLineArgs['nhmsb'] + self.adomain = cmdLineArgs['adomain'] + self.acoup = cmdLineArgs['acoup'] + self.ldasrs = cmdLineArgs['ldasrs'] self.verbose = cmdLineArgs['verbose'] self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : @@ -152,6 +154,20 @@ class LDASsetup: if cmdLineArgs['nymdb'] != 'None' and cmdLineArgs['nhmsb'] != 'None' : self.date = f"{self.nymdb} {self.nhmsb}" self.rqdExeInp[ 'BEG_DATE' ] = self.date + if cmdLineArgs['acoup'] != 'None' : + self.lacase = self.acoup + self.rqdExeInp['LADAS_COUPLING'] = self.lacase + if cmdLineArgs['adomain'] != 'None' : + res_string = self.adomain + if len(res_string) == 4 : + adres = res_string.replace("C", "0") + if len(res_string) == 3 : + adres = res_string.replace("C", "00") + self.adasdomain = adres + if cmdLineArgs['ldasrs'] != 'None' : + ldasrshome_ = cmdLineArgs['ldasrs'].rstrip('/') + assert os.path.isdir(ldasrshome_) # ldas exp for rs should exist + self.ldasrsdir = os.path.abspath(ldasrshome_) # print rqd exe inputs if self.verbose: @@ -159,11 +175,14 @@ class LDASsetup: _printdict(self.rqdExeInp) # nens is an integer and =1 for model run - self.nens = int(self.rqdExeInp['NUM_LDAS_ENSEMBLE']) # fail if Nens's val is not int + 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 + self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) + + ### in cases of ladas coupling self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) self.adas_expdir ='' if self.ladas_coupling > 0 : @@ -171,13 +190,41 @@ class LDASsetup: self.rqdExeInp[ 'ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__bkg' + # couple with adas det if self.ladas_coupling == 1 : self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS' + self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/recycle/holdpredout' + self.rqdExeInp[ 'ENSEMBLE_FORCING' ] = 'NO' + self.nens = 24 + # couple with adas ens if self.ladas_coupling == 2 : self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS4ens' self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/mem' - - self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) + self.rqdExeInp[ 'ENSEMBLE_FORCING' ] = 'YES' + self.nens = 32 + self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens + self.first_ens_id = 1 + self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id + self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.adasdomain +'x6C_CF'+self.adasdomain +'x6C' + self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + self.rsdir = os.path.dirname(self.ldasrsdir) + self.rqdExeInp[ 'RESTART_PATH' ] = self.rsdir + self.rqdExeInp[ 'RESTART_ID' ] = os.path.basename(self.ldasrsdir) + # the following are not in default rqdExeInp list + self.met_hinterp = int(self.rqdExeInp.get('MET_HINTERP',0)) + self.rqdExeInp['MET_HINTERP'] = 0 + self.landassim_dt = str(self.rqdExeInp.get('LANDASSIM_DT', "10800")) + self.rqdExeInp['LANDASSIM_DT'] = "10800" + self.landassim_t0 = str(self.rqdExeInp.get('LANDASSIM_T0', "013000")) + self.rqdExeInp['LANDASSIM_T0'] = "013000" + jobsgmtdef = "00000000 060000" + self.jobsgmt = str(self.rqdExeInp.get('JOB_SGMT', jobsgmtdef )) + self.rqdExeInp['JOB_SGMT'] = jobsgmtdef + self.num_sgmt = int(self.rqdExeInp.get('NUM_SGMT', 1)) + self.rqdExeInp['NUM_SGMT'] = 1 + ### + self.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0)) if self.nens > 1: self.perturb = 1 @@ -234,12 +281,6 @@ class LDASsetup: if 'NUM_SGMT' not in self.rqdExeInp: self.rqdExeInp['NUM_SGMT'] = 1 - # hard set NUM_SGMT and NUM_SGMT - if (self.ladas_coupling > 0) : - if int(self.rqdExeInp['NUM_SGMT']) != 1 : - sys.exit("'NUM_SGMT' should be set to 1 with LADAS_COUPLING") - if self.rqdExeInp['JOB_SGMT'] != "00000000 060000" : - sys.exit("'JOB_SGMT' should be set to 00000000 060000 with LADAS_COUPLING") _years = int(self.rqdExeInp['JOB_SGMT'][0:4]) _months = int(self.rqdExeInp['JOB_SGMT'][4:6]) @@ -1061,6 +1102,9 @@ class LDASsetup: special_nml=[] if 'NML_INPUT_PATH' in self.rqdExeInp : special_nml = glob.glob(self.rqdExeInp['NML_INPUT_PATH']+'/LDASsa_SPECIAL_inputs_*.nml') + if self.ladas_coupling > 0: + special_nml = glob.glob(self.rqdExeInp['NML_INPUT_PATH']+'/'+ self.rqdExeInp['EXP_DOMAIN'] + '/LDASsa_SPECIAL_inputs_*.nml') + for nmlfile in special_nml: shortfile=nmlfile.split('/')[-1] shutil.copy2(nmlfile, self.rundir+'/'+shortfile) @@ -1738,6 +1782,22 @@ def parseCmdLine(): help='replaces BEG_DATE time in exeinp file ', type=str, default='None' ) + p_setup.add_argument( + '--acoup', + help='coupling with adas_det (1) or adas_ens (2)', + type=str, default='None' + ) + p_setup.add_argument( + '--adomain', + help='adas exp domain for coupling ldas EXP_DOMAIN', + type=str, default='None' + ) + p_setup.add_argument( + '--ldasrs', + help='ldas restart exp path/expid', + type=str, default='None' + ) + p_setup.add_argument( '--runmodel', help='Obsolete.', From 07cde3d71059a31fc821ba0e6012483522f474b4 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Fri, 2 May 2025 09:19:33 -0400 Subject: [PATCH 02/36] additional edit for integrated configuration of land-atm DAS (ldas_setup): - renamed new command line arguments - edited comments & help messages for clarity - cleaned up white space and indent --- GEOSldas_App/ldas_setup | 220 +++++++++++++++++++++------------------- 1 file changed, 114 insertions(+), 106 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 85520fb7..0857b19f 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -40,7 +40,8 @@ class LDASsetup: 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', - 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] + 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] + # 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', @@ -69,62 +70,62 @@ class LDASsetup: # sample sub-command # by construction, we can have # either: {'exeinp': False, 'batinp': 'lasgh'} <-- 'lasgh'??? - # or: {'exeinp': True, 'batinp': None} + # or: {'exeinp': True, 'batinp': None } if cmdLineArgs['exeinp']: _printExeInputKeys(rqdExeInpKeys) elif cmdLineArgs['batinp'] : _printRmInputKeys(rqdRmInpKeys, optSlurmInpKeys) else: - raise Exception('not recognized option') + raise Exception('unrecognized option') sys.exit(0) # ------ # ./ldsetup.py setup ... # ------ # Instance variables - self.exeinpfile = cmdLineArgs['exeinpfile'] - self.batinpfile = cmdLineArgs['batinpfile'] - exphome_ = cmdLineArgs['exphome'].rstrip('/') - assert os.path.isdir(exphome_) # exphome should exist - self.exphome = os.path.abspath(exphome_) - self.nymdb = cmdLineArgs['nymdb'] - self.nhmsb = cmdLineArgs['nhmsb'] - self.adomain = cmdLineArgs['adomain'] - self.acoup = cmdLineArgs['acoup'] - self.ldasrs = cmdLineArgs['ldasrs'] - self.verbose = cmdLineArgs['verbose'] - self.runmodel = cmdLineArgs['runmodel'] + self.exeinpfile = cmdLineArgs['exeinpfile'] + self.batinpfile = cmdLineArgs['batinpfile'] + exphome_ = cmdLineArgs['exphome'].rstrip('/') + assert os.path.isdir(exphome_) # exphome should exist + self.exphome = os.path.abspath(exphome_) + self.nymdb = cmdLineArgs['nymdb'] + self.nhmsb = cmdLineArgs['nhmsb'] + self.agcm_res = cmdLineArgs['agcm_res'] + self.ladas_cpl = cmdLineArgs['ladas_cpl'] + self.rstdir = cmdLineArgs['rstdir'] + self.verbose = cmdLineArgs['verbose'] + self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : print('\n The option "--runmodel" is out of date, not necessary anymore. \n') - self.daysperjob = cmdLineArgs['daysperjob'] - self.monthsperjob = cmdLineArgs['monthsperjob'] - self.rqdExeInp = OrderedDict() - self.rqdRmInp = OrderedDict() - self.optRmInp = OrderedDict() - self.rundir = None - self.blddir = None - self.blddirLn = None - self.outdir = None - self.out_path = None - self.inpdir = None - self.exefyl = None - self.islocal = False - self.catch = '' - self.has_mwrtm = False - self.has_vegopacity = False - self.assim = False + self.daysperjob = cmdLineArgs['daysperjob'] + self.monthsperjob = cmdLineArgs['monthsperjob'] + self.rqdExeInp = OrderedDict() + self.rqdRmInp = OrderedDict() + self.optRmInp = OrderedDict() + self.rundir = None + self.blddir = None + self.blddirLn = None + self.outdir = None + self.out_path = None + self.inpdir = None + self.exefyl = None + self.islocal = False + self.catch = '' + self.has_mwrtm = False + self.has_vegopacity = False + self.assim = False self.has_landassim_seed = False - self.has_geos_pert = False - self.nSegments = 1 - self.perturb = 0 - self.first_ens_id = 0 - self.ladas_coupling = 0 - self.in_rstfile = None - self.in_tilefile = 'None' # default string - self.ens_id_width = 6 # _eXXXX - self.bcs_land = '' - self.bcs_geom = '' - self.bcs_landshared = '' + self.has_geos_pert = False + self.nSegments = 1 + self.perturb = 0 + self.first_ens_id = 0 + self.ladas_coupling = 0 + self.in_rstfile = None + self.in_tilefile = 'None' # default string + self.ens_id_width = 6 # _eXXXX + self.bcs_land = '' + self.bcs_geom = '' + self.bcs_landshared = '' # ------ # Read exe input file which is required to set up the dir @@ -154,20 +155,20 @@ class LDASsetup: if cmdLineArgs['nymdb'] != 'None' and cmdLineArgs['nhmsb'] != 'None' : self.date = f"{self.nymdb} {self.nhmsb}" self.rqdExeInp[ 'BEG_DATE' ] = self.date - if cmdLineArgs['acoup'] != 'None' : - self.lacase = self.acoup + if cmdLineArgs['ladas_cpl'] != 'None' : + self.lacase = self.ladas_cpl self.rqdExeInp['LADAS_COUPLING'] = self.lacase - if cmdLineArgs['adomain'] != 'None' : - res_string = self.adomain + if cmdLineArgs['agcm_res'] != 'None' : + res_string = self.agcm_res if len(res_string) == 4 : adres = res_string.replace("C", "0") if len(res_string) == 3 : adres = res_string.replace("C", "00") self.adasdomain = adres - if cmdLineArgs['ldasrs'] != 'None' : - ldasrshome_ = cmdLineArgs['ldasrs'].rstrip('/') - assert os.path.isdir(ldasrshome_) # ldas exp for rs should exist - self.ldasrsdir = os.path.abspath(ldasrshome_) + if cmdLineArgs['rstdir'] != 'None' : + rstdir_ = cmdLineArgs['rstdir'].rstrip('/') # remove trailing '/' + assert os.path.isdir(rstdir_) # ldas exp for rs should exist + self.rstdir = os.path.abspath(rstdir_) # print rqd exe inputs if self.verbose: @@ -182,47 +183,49 @@ class LDASsetup: _mydir = None self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) - ### in cases of ladas coupling - self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) - self.adas_expdir ='' + ### check if ldas is coupled to adas; if so, set input parameters accordingly + self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) + self.adas_expdir = '' if self.ladas_coupling > 0 : - self.adas_expdir = os.path.dirname(self.exphome) - self.rqdExeInp[ 'ADAS_EXPDIR'] = self.adas_expdir - self.adas_expid = os.path.basename(self.adas_expdir) - self.rqdExeInp[ 'MET_TAG' ] = self.adas_expid + '__bkg' - # couple with adas det + self.adas_expdir = os.path.dirname(self.exphome) + self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir + self.adas_expid = os.path.basename(self.adas_expdir) + self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' if self.ladas_coupling == 1 : - self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS' - self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/recycle/holdpredout' - self.rqdExeInp[ 'ENSEMBLE_FORCING' ] = 'NO' - self.nens = 24 - # couple with adas ens - if self.ladas_coupling == 2 : - self.rqdExeInp[ 'EXP_ID' ] = self.adas_expid + '_LDAS4ens' - self.rqdExeInp[ 'MET_PATH' ] = self.adas_expdir +'/atmens/mem' - self.rqdExeInp[ 'ENSEMBLE_FORCING' ] = 'YES' - self.nens = 32 - self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens - self.first_ens_id = 1 - self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id - self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' - self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.adasdomain +'x6C_CF'+self.adasdomain +'x6C' - self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' - self.rsdir = os.path.dirname(self.ldasrsdir) - self.rqdExeInp[ 'RESTART_PATH' ] = self.rsdir - self.rqdExeInp[ 'RESTART_ID' ] = os.path.basename(self.ldasrsdir) + # ldas coupled with determistic component of adas + self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' + self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' + self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' + self.nens = 24 + elif self.ladas_coupling == 2 : + # ldas coupled with ensemble component of adas + self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' + self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' + self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' + self.nens = 32 + else : + exit("Error. Unknown value of ladas_coupling.\n") + self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens + self.first_ens_id = 1 + self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id + self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.adasdomain +'x6C_CF' + self.adasdomain +'x6C' + self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + self.rsdir = os.path.dirname(self.rstdir) + self.rqdExeInp[ 'RESTART_PATH' ] = self.rsdir + self.rqdExeInp[ 'RESTART_ID' ] = os.path.basename(self.rstdir) # the following are not in default rqdExeInp list - self.met_hinterp = int(self.rqdExeInp.get('MET_HINTERP',0)) - self.rqdExeInp['MET_HINTERP'] = 0 - self.landassim_dt = str(self.rqdExeInp.get('LANDASSIM_DT', "10800")) - self.rqdExeInp['LANDASSIM_DT'] = "10800" - self.landassim_t0 = str(self.rqdExeInp.get('LANDASSIM_T0', "013000")) - self.rqdExeInp['LANDASSIM_T0'] = "013000" - jobsgmtdef = "00000000 060000" - self.jobsgmt = str(self.rqdExeInp.get('JOB_SGMT', jobsgmtdef )) - self.rqdExeInp['JOB_SGMT'] = jobsgmtdef - self.num_sgmt = int(self.rqdExeInp.get('NUM_SGMT', 1)) - self.rqdExeInp['NUM_SGMT'] = 1 + self.met_hinterp = int(self.rqdExeInp.get('MET_HINTERP',0)) + self.rqdExeInp['MET_HINTERP'] = 0 + self.landassim_dt = str(self.rqdExeInp.get('LANDASSIM_DT', "10800")) + self.rqdExeInp['LANDASSIM_DT'] = "10800" + self.landassim_t0 = str(self.rqdExeInp.get('LANDASSIM_T0', "013000")) + self.rqdExeInp['LANDASSIM_T0'] = "013000" + jobsgmtdef = "00000000 060000" + self.jobsgmt = str(self.rqdExeInp.get('JOB_SGMT', jobsgmtdef )) + self.rqdExeInp['JOB_SGMT'] = jobsgmtdef + self.num_sgmt = int(self.rqdExeInp.get('NUM_SGMT', 1)) + self.rqdExeInp['NUM_SGMT'] = 1 ### self.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0)) @@ -712,7 +715,7 @@ class LDASsetup: status = True return status - # create link, BCs , restarts + # create links to BCs, restarts, met forcing, ... def createLnRstBc(self) : # link bld dir status = False @@ -1604,12 +1607,13 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Coupling of LDAS to ADAS ("LADAS"): #') print ('# #') print ('# 0 -- LDAS not coupled with ADAS (default) #') - print ('# 1 -- LDAS coupled with central member of ADAS #') + print ('# 1 -- LDAS coupled with central (det) member of ADAS #') print ('# 2 -- LDAS coupled with ens component of ADAS #') print ('# #') - print ('# Requirements for LADAS_COUPLING > 0: #') + print ('# Requirements for LADAS_COUPLING > 0 are as follows, #') + print ('# with most requirements hardwired into ldas_setup: #') print ('# #') - print ('# (0) Specify ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') + print ('# (0) ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') print ('# #') print ('# (1) BEG_DATE must be consistent with first cycle date #') print ('# and time of ADAS experiment (time is typically #') @@ -1635,7 +1639,8 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# (7) HISTORY: #') print ('# - instantaneous "catch_progn_incr" must be in #') print ('# HISTORY collection #') - print ('# - time step must match that of LDAS analysis #') + print ('# - time step must be consistent with that of #') + print ('# LDAS analysis #') print ('# - for LADAS_COUPLING=2, HISTORY must include #') print ('# "catch_progn_incr[ENS_INDEX]" #') print ('# #') @@ -1741,7 +1746,7 @@ def parseCmdLine(): ) group.add_argument( '--batinp', - help='print sample input file for SLURM ', + help='print sample input file for the resource manager (SLURM)', action='store_true', ) # subparser: setup command @@ -1750,7 +1755,7 @@ def parseCmdLine(): help='setup LDAS experiment', description="The 'setup' sub-command is used to setup a GEOSldas " \ "experiment. The positional argument 'exphome' is used to create " \ - "work_path (exphome+/output) and run_path (exphome+/run)." + "work_path (=exphome+/output) and run_path (=exphome+/run)." ) p_setup.add_argument( '-v', @@ -1767,37 +1772,40 @@ def parseCmdLine(): 'batinpfile', help='input file with arguments for SLURM', ) + + # the following command line arguments, if present, take precedence over what + # is specified in the exeinp and batinp files p_setup.add_argument( '--account', - help='replace computing/sponsor account in batinp file', + help='overwrites computing/sponsor account from batinp file', type=str, default='None' ) p_setup.add_argument( '--nymdb', - help='replaces BEG_DATE date in exeinp file ', + help='overwrites date in BEG_DATE from exeinp file', type=str, default='None' ) p_setup.add_argument( '--nhmsb', - help='replaces BEG_DATE time in exeinp file ', + help='overwrites time in BEG_DATE from exeinp file', type=str, default='None' ) p_setup.add_argument( - '--acoup', - help='coupling with adas_det (1) or adas_ens (2)', + '--ladas_cpl', + help='specifies LDAS/ADAS coupling mode: (1) ADAS deterministic member or (2) ADAS ensemble', type=str, default='None' ) p_setup.add_argument( - '--adomain', - help='adas exp domain for coupling ldas EXP_DOMAIN', + '--agcm_res', + help='specifies AGCM resolution of coupled ADAS component', type=str, default='None' ) p_setup.add_argument( - '--ldasrs', - help='ldas restart exp path/expid', + '--rstdir', + help='specifies LDAS restart dir (exp path/exp id)', type=str, default='None' ) - + p_setup.add_argument( '--runmodel', help='Obsolete.', From 5bdce17cd669c37f2813c71747e922da1686be56 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Fri, 2 May 2025 13:23:43 -0400 Subject: [PATCH 03/36] update input strings for agcm_res --- GEOSldas_App/ldas_setup | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 0857b19f..9f5900b5 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -159,12 +159,7 @@ class LDASsetup: self.lacase = self.ladas_cpl self.rqdExeInp['LADAS_COUPLING'] = self.lacase if cmdLineArgs['agcm_res'] != 'None' : - res_string = self.agcm_res - if len(res_string) == 4 : - adres = res_string.replace("C", "0") - if len(res_string) == 3 : - adres = res_string.replace("C", "00") - self.adasdomain = adres + self.adasdomain = self.agcm_res if cmdLineArgs['rstdir'] != 'None' : rstdir_ = cmdLineArgs['rstdir'].rstrip('/') # remove trailing '/' assert os.path.isdir(rstdir_) # ldas exp for rs should exist From 29f77d80d9abae22f62e5bfb6bc27e845485a1cb Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Mon, 5 May 2025 19:55:18 -0400 Subject: [PATCH 04/36] add land BCs version input for ladas edit lines responding to comments --- GEOSldas_App/ldas_setup | 45 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 9f5900b5..b06d60d9 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -91,8 +91,9 @@ class LDASsetup: self.nymdb = cmdLineArgs['nymdb'] self.nhmsb = cmdLineArgs['nhmsb'] self.agcm_res = cmdLineArgs['agcm_res'] + self.landBC_ver = cmdLineArgs['landBC_ver'] self.ladas_cpl = cmdLineArgs['ladas_cpl'] - self.rstdir = cmdLineArgs['rstdir'] + self.rstloc = cmdLineArgs['rstloc'] self.verbose = cmdLineArgs['verbose'] self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : @@ -160,10 +161,12 @@ class LDASsetup: self.rqdExeInp['LADAS_COUPLING'] = self.lacase if cmdLineArgs['agcm_res'] != 'None' : self.adasdomain = self.agcm_res - if cmdLineArgs['rstdir'] != 'None' : - rstdir_ = cmdLineArgs['rstdir'].rstrip('/') # remove trailing '/' - assert os.path.isdir(rstdir_) # ldas exp for rs should exist - self.rstdir = os.path.abspath(rstdir_) + if cmdLineArgs['landBC_ver'] != 'None' : + self.landbcver = self.landBC_ver + if cmdLineArgs['rstloc'] != 'None' : + rstloc_ = cmdLineArgs['rstloc'].rstrip('/') # remove trailing '/' + assert os.path.isdir(rstloc_) # ldas exp for rs should exist + self.rstloc = os.path.abspath(rstloc_) # print rqd exe inputs if self.verbose: @@ -191,35 +194,32 @@ class LDASsetup: self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' - self.nens = 24 + self.nens = 24 elif self.ladas_coupling == 2 : # ldas coupled with ensemble component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' - self.nens = 32 + self.nens = 32 else : exit("Error. Unknown value of ladas_coupling.\n") self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens self.first_ens_id = 1 self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id - self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + uptotiles = os.path.dirname(self.rqdExeInp['BCS_PATH'].rstrip('/')) + self.rqdExeInp['BCS_PATH'] = uptotiles + '/' + self.landbcver + if self.landbcver == "Icarus-NLv3" : + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.adasdomain +'x6C_CF' + self.adasdomain +'x6C' self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' - self.rsdir = os.path.dirname(self.rstdir) - self.rqdExeInp[ 'RESTART_PATH' ] = self.rsdir - self.rqdExeInp[ 'RESTART_ID' ] = os.path.basename(self.rstdir) + self.rqdExeInp[ 'RESTART_PATH' ] = os.path.dirname(self.rstloc) + self.rqdExeInp[ 'RESTART_ID' ] = os.path.basename(self.rstloc) # the following are not in default rqdExeInp list - self.met_hinterp = int(self.rqdExeInp.get('MET_HINTERP',0)) self.rqdExeInp['MET_HINTERP'] = 0 - self.landassim_dt = str(self.rqdExeInp.get('LANDASSIM_DT', "10800")) self.rqdExeInp['LANDASSIM_DT'] = "10800" - self.landassim_t0 = str(self.rqdExeInp.get('LANDASSIM_T0', "013000")) self.rqdExeInp['LANDASSIM_T0'] = "013000" - jobsgmtdef = "00000000 060000" - self.jobsgmt = str(self.rqdExeInp.get('JOB_SGMT', jobsgmtdef )) - self.rqdExeInp['JOB_SGMT'] = jobsgmtdef - self.num_sgmt = int(self.rqdExeInp.get('NUM_SGMT', 1)) + self.rqdExeInp['JOB_SGMT'] = "00000000 060000" self.rqdExeInp['NUM_SGMT'] = 1 ### @@ -1796,8 +1796,13 @@ def parseCmdLine(): type=str, default='None' ) p_setup.add_argument( - '--rstdir', - help='specifies LDAS restart dir (exp path/exp id)', + '--landBC_ver', + help='specifies land BCs version of coupled ADAS component', + type=str, default='None' + ) + p_setup.add_argument( + '--rstloc', + help='specifies LDAS restart location (exp path/exp id)', type=str, default='None' ) From a1a2533450bb66cf06c3d396e0f26739d15e813a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 6 May 2025 11:57:01 -0400 Subject: [PATCH 05/36] cleanup of command line args for land-atm DAS config (ldas_setup) --- GEOSldas_App/ldas_setup | 121 +++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index b06d60d9..60593159 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -69,11 +69,11 @@ class LDASsetup: if 'exeinp' in cmdLineArgs: # sample sub-command # by construction, we can have - # either: {'exeinp': False, 'batinp': 'lasgh'} <-- 'lasgh'??? - # or: {'exeinp': True, 'batinp': None } - if cmdLineArgs['exeinp']: + # either: {'exeinp': False, 'batinp': True } + # or: {'exeinp': True, 'batinp': False} + if cmdLineArgs['exeinp']: _printExeInputKeys(rqdExeInpKeys) - elif cmdLineArgs['batinp'] : + elif cmdLineArgs['batinp']: _printRmInputKeys(rqdRmInpKeys, optSlurmInpKeys) else: raise Exception('unrecognized option') @@ -88,18 +88,23 @@ class LDASsetup: exphome_ = cmdLineArgs['exphome'].rstrip('/') assert os.path.isdir(exphome_) # exphome should exist self.exphome = os.path.abspath(exphome_) + self.verbose = cmdLineArgs['verbose'] + + # command line args for coupled land-atm DAS self.nymdb = cmdLineArgs['nymdb'] self.nhmsb = cmdLineArgs['nhmsb'] self.agcm_res = cmdLineArgs['agcm_res'] - self.landBC_ver = cmdLineArgs['landBC_ver'] + self.bcs_version = cmdLineArgs['bcs_version'] self.ladas_cpl = cmdLineArgs['ladas_cpl'] self.rstloc = cmdLineArgs['rstloc'] - self.verbose = cmdLineArgs['verbose'] + + # obsolete command line args self.runmodel = cmdLineArgs['runmodel'] if self.runmodel : print('\n The option "--runmodel" is out of date, not necessary anymore. \n') self.daysperjob = cmdLineArgs['daysperjob'] self.monthsperjob = cmdLineArgs['monthsperjob'] + self.rqdExeInp = OrderedDict() self.rqdRmInp = OrderedDict() self.optRmInp = OrderedDict() @@ -124,9 +129,9 @@ class LDASsetup: self.in_rstfile = None self.in_tilefile = 'None' # default string self.ens_id_width = 6 # _eXXXX - self.bcs_land = '' - self.bcs_geom = '' - self.bcs_landshared = '' + self.bcs_dir_land = '' + self.bcs_dir_geom = '' + self.bcs_dir_landshared = '' # ------ # Read exe input file which is required to set up the dir @@ -157,12 +162,7 @@ class LDASsetup: self.date = f"{self.nymdb} {self.nhmsb}" self.rqdExeInp[ 'BEG_DATE' ] = self.date if cmdLineArgs['ladas_cpl'] != 'None' : - self.lacase = self.ladas_cpl - self.rqdExeInp['LADAS_COUPLING'] = self.lacase - if cmdLineArgs['agcm_res'] != 'None' : - self.adasdomain = self.agcm_res - if cmdLineArgs['landBC_ver'] != 'None' : - self.landbcver = self.landBC_ver + self.rqdExeInp['LADAS_COUPLING'] = self.ladas_cpl if cmdLineArgs['rstloc'] != 'None' : rstloc_ = cmdLineArgs['rstloc'].rstrip('/') # remove trailing '/' assert os.path.isdir(rstloc_) # ldas exp for rs should exist @@ -189,32 +189,34 @@ class LDASsetup: self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' - if self.ladas_coupling == 1 : + if self.ladas_coupling == 1 : # ldas coupled with determistic component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' - self.nens = 24 + self.nens = 24 elif self.ladas_coupling == 2 : # ldas coupled with ensemble component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' - self.nens = 32 + self.nens = 32 else : exit("Error. Unknown value of ladas_coupling.\n") self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens self.first_ens_id = 1 self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id - self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' + self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + + # when coupled to ADAS, "BCS_PATH" in exeinp file must EXCLUDE bcs version info uptotiles = os.path.dirname(self.rqdExeInp['BCS_PATH'].rstrip('/')) - self.rqdExeInp['BCS_PATH'] = uptotiles + '/' + self.landbcver - if self.landbcver == "Icarus-NLv3" : - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' - self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.adasdomain +'x6C_CF' + self.adasdomain +'x6C' - self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.adasdomain +'x6C_GLOBAL' - self.rqdExeInp[ 'RESTART_PATH' ] = os.path.dirname(self.rstloc) - self.rqdExeInp[ 'RESTART_ID' ] = os.path.basename(self.rstloc) + self.rqdExeInp['BCS_PATH'] = uptotiles + '/' + self.bcs_version + if self.bcs_version == "Icarus-NLv3" : + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' + self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' + self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) + self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) # the following are not in default rqdExeInp list self.rqdExeInp['MET_HINTERP'] = 0 self.rqdExeInp['LANDASSIM_DT'] = "10800" @@ -230,7 +232,7 @@ class LDASsetup: # if self.ens_id_width = 4, _width = '_e%04d' _width = '_e%0{}d'.format(self.ens_id_width-2) # self.ensids will be a list of [_e0000, _e0001, ...] - self.ensids = [ _width%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] + self.ensids = [ _width%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] if (self.nens == 1) : self.ensdirs_avg = self.ensdirs self.ensids=[''] @@ -303,11 +305,12 @@ class LDASsetup: self.endDates.insert(-1,_d) _d = _d+ _difftime - # make sure path is path - self.bcs_land = self.rqdExeInp['BCS_PATH']+ '/land/' + self.rqdExeInp['BCS_RESOLUTION']+'/' - self.bcs_geom = self.rqdExeInp['BCS_PATH']+ '/geometry/' + self.rqdExeInp['BCS_RESOLUTION']+'/' - self.bcs_landshared = self.rqdExeInp['BCS_PATH']+ '/land/shared/' + # assemble bcs sub-directories + self.bcs_dir_land = self.rqdExeInp['BCS_PATH']+ '/land/' + self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_dir_geom = self.rqdExeInp['BCS_PATH']+ '/geometry/' + self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_dir_landshared = self.rqdExeInp['BCS_PATH']+ '/land/shared/' + # make sure MET_PATH and RESTART_PATH have trailing '/' if self.rqdExeInp['MET_PATH'][-1] != '/': self.rqdExeInp['MET_PATH'] = self.rqdExeInp['MET_PATH']+'/' if self.rqdExeInp['RESTART_PATH'][-1] != '/': @@ -315,7 +318,7 @@ class LDASsetup: # make sure catchment and vegdyn restart files ( at least one for each) exist if 'CATCH_DEF_FILE' not in self.rqdExeInp: - self.rqdExeInp['CATCH_DEF_FILE']= self.bcs_land + 'clsm/catchment.def' + self.rqdExeInp['CATCH_DEF_FILE']= self.bcs_dir_land + 'clsm/catchment.def' assert os.path.isfile(self.rqdExeInp['CATCH_DEF_FILE']),"[%s] file does not exist " % self.rqdExeInp['CATCH_DEF_FILE'] self.rqdExeInp['RST_FROM_GLOBAL'] = 1 @@ -334,21 +337,21 @@ class LDASsetup: self.rqdExeInp['LNFM_FILE'] = '' if int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1 : - self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] - self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] - tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE']= glob.glob(self.bcs_dir_geom + '*.til')[0] + self.rqdExeInp['GRN_FILE'] = glob.glob(self.bcs_dir_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE'] = glob.glob(self.bcs_dir_land + 'lai_clim_*.data')[0] + tmp_ = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data') if (len(tmp_) ==1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_dir_land + 'ndvi_clim_*.data')[0] + self.rqdExeInp['NIRDF_FILE'] = glob.glob(self.bcs_dir_land + 'nirdf_*.dat')[0] + self.rqdExeInp['VISDF_FILE'] = glob.glob(self.bcs_dir_land + 'visdf_*.dat')[0] else : inpdir=self.rqdExeInp['RESTART_PATH']+self.rqdExeInp['RESTART_ID']+'/input/' self.rqdExeInp['TILING_FILE'] =os.path.realpath(glob.glob(inpdir+'*tile.data')[0]) self.rqdExeInp['GRN_FILE']= os.path.realpath(glob.glob(inpdir+'green*data')[0]) self.rqdExeInp['LAI_FILE']= os.path.realpath(glob.glob(inpdir+'lai*data')[0]) - tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') + tmp_ = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] self.rqdExeInp['NDVI_FILE']= os.path.realpath(glob.glob(inpdir+'ndvi*data')[0]) @@ -372,16 +375,16 @@ class LDASsetup: if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] - self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] - tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE']= glob.glob(self.bcs_dir_geom + '*.til')[0] + self.rqdExeInp['GRN_FILE'] = glob.glob(self.bcs_dir_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE'] = glob.glob(self.bcs_dir_land + 'lai_clim_*.data')[0] + tmp_ = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_land + 'lnfm_clim_*.data')[0] - self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] + self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_dir_land + 'ndvi_clim_*.data')[0] + self.rqdExeInp['NIRDF_FILE'] = glob.glob(self.bcs_dir_land + 'nirdf_*.dat')[0] + self.rqdExeInp['VISDF_FILE'] = glob.glob(self.bcs_dir_land + 'visdf_*.dat')[0] if 'GRIDNAME' not in self.rqdExeInp : tmptile =self.rqdExeInp['TILING_FILE'] @@ -846,7 +849,7 @@ class LDASsetup: os.symlink(bc,myBC) if ("catchcn" in self.catch): - os.symlink(self.bcs_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ + os.symlink(self.bcs_dir_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') # create and link restart @@ -966,16 +969,16 @@ class LDASsetup: if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) == 0 or int(self.rqdExeInp['RESTART']) == 2 : - vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_dir_land + 'vegdyn_*.dat')[0] catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] else : # RESTART == 1 catchRstFile = rstpath+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 vegdynRstFile= rstpath+ensdir +'/'+self.rqdExeInp['RESTART_ID']+ '.vegdyn_internal_rst' if not os.path.isfile(vegdynRstFile): # no vegdyn restart from LDASsa if not os.path.isfile(vegdynRstFile0): - vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_dir_land + 'vegdyn_*.dat')[0] else : - vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_dir_land + 'vegdyn_*.dat')[0] catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] # catchment restart file @@ -1585,6 +1588,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# LAND BOUNDARY CONDITIONS (BCS) #') print ('# #') print ('# Path to and (atmospheric) resolution of BCS. #') + print ('# Path includes BCS_VERSION (unless LADAS_COUPLING>0). #') print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') @@ -1787,25 +1791,26 @@ def parseCmdLine(): ) p_setup.add_argument( '--ladas_cpl', - help='specifies LDAS/ADAS coupling mode: (1) ADAS deterministic member or (2) ADAS ensemble', + help='land-atm DAS coupling mode: LDAS coupled with (1) ADAS deterministic member or (2) ADAS ensemble', type=str, default='None' ) p_setup.add_argument( '--agcm_res', - help='specifies AGCM resolution of coupled ADAS component', + help='AGCM resolution associated with boundary conditions', type=str, default='None' ) p_setup.add_argument( - '--landBC_ver', - help='specifies land BCs version of coupled ADAS component', + '--bcs_version', + help='boundary conditions version', type=str, default='None' ) p_setup.add_argument( '--rstloc', - help='specifies LDAS restart location (exp path/exp id)', + help='location of LDAS restarts (restart_path/restart_id)', type=str, default='None' ) - + + # obsolete command line args p_setup.add_argument( '--runmodel', help='Obsolete.', From 2443b5a0605abf89afb37816c34550f373853bd9 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 6 May 2025 12:03:41 -0400 Subject: [PATCH 06/36] updated CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 949a160c..52e033b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added more default settings and command line arguments for integrated land-atm DAS setup ([PR #94](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/94)). + ### Changed ### Fixed From 7742280cc6af5006aa7a9472fcabef5cd7cb94c6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 6 May 2025 12:10:11 -0400 Subject: [PATCH 07/36] changed handling of N_ens for coupled land-atm DAS setup (ldas_setup) --- GEOSldas_App/ldas_setup | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 60593159..22c14376 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -181,7 +181,7 @@ class LDASsetup: _mydir = None self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) - ### check if ldas is coupled to adas; if so, set input parameters accordingly + ### check if ldas is coupled to adas; if so, set/overwrite input parameters accordingly self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) self.adas_expdir = '' if self.ladas_coupling > 0 : @@ -194,13 +194,12 @@ class LDASsetup: self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' - self.nens = 24 elif self.ladas_coupling == 2 : # ldas coupled with ensemble component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' - self.nens = 32 + self.nens = 32 # for now, hardwire nens for atm ens else : exit("Error. Unknown value of ladas_coupling.\n") self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens From 8a7c7fcf97fc1fac6df0e8fc48280d09e16e90f3 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 6 May 2025 16:57:46 -0400 Subject: [PATCH 08/36] add README on construction of exeinp.txt for LADAS remove outdated sample files --- .../LADAS/HISTORY.rc.atmens | 1083 ----------------- .../LADAS/HISTORY.rc.central | 98 -- .../LADAS/README.exeinp.txt.forladas | 39 + .../LADAS/exeinp.txt.Hy4dEnVar.atmens | 48 - .../LADAS/exeinp.txt.Hy4dEnVar.central | 50 - 5 files changed, 39 insertions(+), 1279 deletions(-) delete mode 100644 GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.atmens delete mode 100644 GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.central create mode 100644 GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas delete mode 100644 GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens delete mode 100644 GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central diff --git a/GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.atmens b/GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.atmens deleted file mode 100644 index 5b24ddf9..00000000 --- a/GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.atmens +++ /dev/null @@ -1,1083 +0,0 @@ - -# -# Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) -# -# - This sample HISTORY.rc is for the GEOSldas instance that is weakly coupled with the -# atmospheric ensemble component of the Hybrid-4DEnVar ADAS (ADASens). -# -# - The sample file was generated with the utility script -# "GEOSldas/src/Components/GEOSldas_GridComp/GEOSldas_App/util/config/generate_catchincr_hist.py". -# -# - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in -# ensemble space, which is needed by ADASens. -# -# - The IDs of the ensemble members and their total number in GEOSldas must match -# those of ADASens. -# -# - The "catch_progn_incr" output is in tile space, which must be the same for -# GEOSldas and ADASens. -# -# -################################################################################## - -EXPID: MyGEOSldasAtmEns - -COLLECTIONS: -'catch_progn_incr0001' -'catch_progn_incr0002' -'catch_progn_incr0003' -'catch_progn_incr0004' -'catch_progn_incr0005' -'catch_progn_incr0006' -'catch_progn_incr0007' -'catch_progn_incr0008' -'catch_progn_incr0009' -'catch_progn_incr0010' -'catch_progn_incr0011' -'catch_progn_incr0012' -'catch_progn_incr0013' -'catch_progn_incr0014' -'catch_progn_incr0015' -'catch_progn_incr0016' -'catch_progn_incr0017' -'catch_progn_incr0018' -'catch_progn_incr0019' -'catch_progn_incr0020' -'catch_progn_incr0021' -'catch_progn_incr0022' -'catch_progn_incr0023' -'catch_progn_incr0024' -'catch_progn_incr0025' -'catch_progn_incr0026' -'catch_progn_incr0027' -'catch_progn_incr0028' -'catch_progn_incr0029' -'catch_progn_incr0030' -'catch_progn_incr0031' -'catch_progn_incr0032' - -:: -catch_progn_incr0001.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0001.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0001.mode: 'instantaneous', -catch_progn_incr0001.frequency: 030000, -catch_progn_incr0001.ref_time: 013000, -catch_progn_incr0001.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0001' , - 'TCFTRN_INCR' , 'CATCHINCR_e0001' , - 'TCFWLT_INCR' , 'CATCHINCR_e0001' , - 'QCFSAT_INCR' , 'CATCHINCR_e0001' , - 'QCFTRN_INCR' , 'CATCHINCR_e0001' , - 'QCFWLT_INCR' , 'CATCHINCR_e0001' , - 'CAPAC_INCR' , 'CATCHINCR_e0001' , - 'CATDEF_INCR' , 'CATCHINCR_e0001' , - 'RZEXC_INCR' , 'CATCHINCR_e0001' , - 'SRFEXC_INCR' , 'CATCHINCR_e0001' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0001' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0001' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0001' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0001' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0001' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0001' , - 'WESNN1_INCR' , 'CATCHINCR_e0001' , - 'WESNN2_INCR' , 'CATCHINCR_e0001' , - 'WESNN3_INCR' , 'CATCHINCR_e0001' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0001' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0001' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0001' , - 'SNDZN1_INCR' , 'CATCHINCR_e0001' , - 'SNDZN2_INCR' , 'CATCHINCR_e0001' , - 'SNDZN3_INCR' , 'CATCHINCR_e0001' , - -:: -catch_progn_incr0002.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0002.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0002.mode: 'instantaneous', -catch_progn_incr0002.frequency: 030000, -catch_progn_incr0002.ref_time: 013000, -catch_progn_incr0002.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0002' , - 'TCFTRN_INCR' , 'CATCHINCR_e0002' , - 'TCFWLT_INCR' , 'CATCHINCR_e0002' , - 'QCFSAT_INCR' , 'CATCHINCR_e0002' , - 'QCFTRN_INCR' , 'CATCHINCR_e0002' , - 'QCFWLT_INCR' , 'CATCHINCR_e0002' , - 'CAPAC_INCR' , 'CATCHINCR_e0002' , - 'CATDEF_INCR' , 'CATCHINCR_e0002' , - 'RZEXC_INCR' , 'CATCHINCR_e0002' , - 'SRFEXC_INCR' , 'CATCHINCR_e0002' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0002' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0002' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0002' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0002' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0002' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0002' , - 'WESNN1_INCR' , 'CATCHINCR_e0002' , - 'WESNN2_INCR' , 'CATCHINCR_e0002' , - 'WESNN3_INCR' , 'CATCHINCR_e0002' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0002' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0002' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0002' , - 'SNDZN1_INCR' , 'CATCHINCR_e0002' , - 'SNDZN2_INCR' , 'CATCHINCR_e0002' , - 'SNDZN3_INCR' , 'CATCHINCR_e0002' , - -:: -catch_progn_incr0003.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0003.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0003.mode: 'instantaneous', -catch_progn_incr0003.frequency: 030000, -catch_progn_incr0003.ref_time: 013000, -catch_progn_incr0003.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0003' , - 'TCFTRN_INCR' , 'CATCHINCR_e0003' , - 'TCFWLT_INCR' , 'CATCHINCR_e0003' , - 'QCFSAT_INCR' , 'CATCHINCR_e0003' , - 'QCFTRN_INCR' , 'CATCHINCR_e0003' , - 'QCFWLT_INCR' , 'CATCHINCR_e0003' , - 'CAPAC_INCR' , 'CATCHINCR_e0003' , - 'CATDEF_INCR' , 'CATCHINCR_e0003' , - 'RZEXC_INCR' , 'CATCHINCR_e0003' , - 'SRFEXC_INCR' , 'CATCHINCR_e0003' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0003' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0003' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0003' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0003' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0003' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0003' , - 'WESNN1_INCR' , 'CATCHINCR_e0003' , - 'WESNN2_INCR' , 'CATCHINCR_e0003' , - 'WESNN3_INCR' , 'CATCHINCR_e0003' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0003' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0003' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0003' , - 'SNDZN1_INCR' , 'CATCHINCR_e0003' , - 'SNDZN2_INCR' , 'CATCHINCR_e0003' , - 'SNDZN3_INCR' , 'CATCHINCR_e0003' , - -:: -catch_progn_incr0004.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0004.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0004.mode: 'instantaneous', -catch_progn_incr0004.frequency: 030000, -catch_progn_incr0004.ref_time: 013000, -catch_progn_incr0004.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0004' , - 'TCFTRN_INCR' , 'CATCHINCR_e0004' , - 'TCFWLT_INCR' , 'CATCHINCR_e0004' , - 'QCFSAT_INCR' , 'CATCHINCR_e0004' , - 'QCFTRN_INCR' , 'CATCHINCR_e0004' , - 'QCFWLT_INCR' , 'CATCHINCR_e0004' , - 'CAPAC_INCR' , 'CATCHINCR_e0004' , - 'CATDEF_INCR' , 'CATCHINCR_e0004' , - 'RZEXC_INCR' , 'CATCHINCR_e0004' , - 'SRFEXC_INCR' , 'CATCHINCR_e0004' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0004' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0004' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0004' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0004' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0004' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0004' , - 'WESNN1_INCR' , 'CATCHINCR_e0004' , - 'WESNN2_INCR' , 'CATCHINCR_e0004' , - 'WESNN3_INCR' , 'CATCHINCR_e0004' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0004' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0004' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0004' , - 'SNDZN1_INCR' , 'CATCHINCR_e0004' , - 'SNDZN2_INCR' , 'CATCHINCR_e0004' , - 'SNDZN3_INCR' , 'CATCHINCR_e0004' , - -:: -catch_progn_incr0005.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0005.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0005.mode: 'instantaneous', -catch_progn_incr0005.frequency: 030000, -catch_progn_incr0005.ref_time: 013000, -catch_progn_incr0005.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0005' , - 'TCFTRN_INCR' , 'CATCHINCR_e0005' , - 'TCFWLT_INCR' , 'CATCHINCR_e0005' , - 'QCFSAT_INCR' , 'CATCHINCR_e0005' , - 'QCFTRN_INCR' , 'CATCHINCR_e0005' , - 'QCFWLT_INCR' , 'CATCHINCR_e0005' , - 'CAPAC_INCR' , 'CATCHINCR_e0005' , - 'CATDEF_INCR' , 'CATCHINCR_e0005' , - 'RZEXC_INCR' , 'CATCHINCR_e0005' , - 'SRFEXC_INCR' , 'CATCHINCR_e0005' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0005' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0005' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0005' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0005' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0005' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0005' , - 'WESNN1_INCR' , 'CATCHINCR_e0005' , - 'WESNN2_INCR' , 'CATCHINCR_e0005' , - 'WESNN3_INCR' , 'CATCHINCR_e0005' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0005' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0005' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0005' , - 'SNDZN1_INCR' , 'CATCHINCR_e0005' , - 'SNDZN2_INCR' , 'CATCHINCR_e0005' , - 'SNDZN3_INCR' , 'CATCHINCR_e0005' , - -:: -catch_progn_incr0006.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0006.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0006.mode: 'instantaneous', -catch_progn_incr0006.frequency: 030000, -catch_progn_incr0006.ref_time: 013000, -catch_progn_incr0006.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0006' , - 'TCFTRN_INCR' , 'CATCHINCR_e0006' , - 'TCFWLT_INCR' , 'CATCHINCR_e0006' , - 'QCFSAT_INCR' , 'CATCHINCR_e0006' , - 'QCFTRN_INCR' , 'CATCHINCR_e0006' , - 'QCFWLT_INCR' , 'CATCHINCR_e0006' , - 'CAPAC_INCR' , 'CATCHINCR_e0006' , - 'CATDEF_INCR' , 'CATCHINCR_e0006' , - 'RZEXC_INCR' , 'CATCHINCR_e0006' , - 'SRFEXC_INCR' , 'CATCHINCR_e0006' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0006' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0006' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0006' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0006' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0006' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0006' , - 'WESNN1_INCR' , 'CATCHINCR_e0006' , - 'WESNN2_INCR' , 'CATCHINCR_e0006' , - 'WESNN3_INCR' , 'CATCHINCR_e0006' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0006' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0006' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0006' , - 'SNDZN1_INCR' , 'CATCHINCR_e0006' , - 'SNDZN2_INCR' , 'CATCHINCR_e0006' , - 'SNDZN3_INCR' , 'CATCHINCR_e0006' , - -:: -catch_progn_incr0007.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0007.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0007.mode: 'instantaneous', -catch_progn_incr0007.frequency: 030000, -catch_progn_incr0007.ref_time: 013000, -catch_progn_incr0007.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0007' , - 'TCFTRN_INCR' , 'CATCHINCR_e0007' , - 'TCFWLT_INCR' , 'CATCHINCR_e0007' , - 'QCFSAT_INCR' , 'CATCHINCR_e0007' , - 'QCFTRN_INCR' , 'CATCHINCR_e0007' , - 'QCFWLT_INCR' , 'CATCHINCR_e0007' , - 'CAPAC_INCR' , 'CATCHINCR_e0007' , - 'CATDEF_INCR' , 'CATCHINCR_e0007' , - 'RZEXC_INCR' , 'CATCHINCR_e0007' , - 'SRFEXC_INCR' , 'CATCHINCR_e0007' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0007' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0007' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0007' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0007' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0007' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0007' , - 'WESNN1_INCR' , 'CATCHINCR_e0007' , - 'WESNN2_INCR' , 'CATCHINCR_e0007' , - 'WESNN3_INCR' , 'CATCHINCR_e0007' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0007' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0007' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0007' , - 'SNDZN1_INCR' , 'CATCHINCR_e0007' , - 'SNDZN2_INCR' , 'CATCHINCR_e0007' , - 'SNDZN3_INCR' , 'CATCHINCR_e0007' , - -:: -catch_progn_incr0008.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0008.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0008.mode: 'instantaneous', -catch_progn_incr0008.frequency: 030000, -catch_progn_incr0008.ref_time: 013000, -catch_progn_incr0008.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0008' , - 'TCFTRN_INCR' , 'CATCHINCR_e0008' , - 'TCFWLT_INCR' , 'CATCHINCR_e0008' , - 'QCFSAT_INCR' , 'CATCHINCR_e0008' , - 'QCFTRN_INCR' , 'CATCHINCR_e0008' , - 'QCFWLT_INCR' , 'CATCHINCR_e0008' , - 'CAPAC_INCR' , 'CATCHINCR_e0008' , - 'CATDEF_INCR' , 'CATCHINCR_e0008' , - 'RZEXC_INCR' , 'CATCHINCR_e0008' , - 'SRFEXC_INCR' , 'CATCHINCR_e0008' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0008' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0008' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0008' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0008' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0008' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0008' , - 'WESNN1_INCR' , 'CATCHINCR_e0008' , - 'WESNN2_INCR' , 'CATCHINCR_e0008' , - 'WESNN3_INCR' , 'CATCHINCR_e0008' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0008' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0008' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0008' , - 'SNDZN1_INCR' , 'CATCHINCR_e0008' , - 'SNDZN2_INCR' , 'CATCHINCR_e0008' , - 'SNDZN3_INCR' , 'CATCHINCR_e0008' , - -:: -catch_progn_incr0009.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0009.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0009.mode: 'instantaneous', -catch_progn_incr0009.frequency: 030000, -catch_progn_incr0009.ref_time: 013000, -catch_progn_incr0009.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0009' , - 'TCFTRN_INCR' , 'CATCHINCR_e0009' , - 'TCFWLT_INCR' , 'CATCHINCR_e0009' , - 'QCFSAT_INCR' , 'CATCHINCR_e0009' , - 'QCFTRN_INCR' , 'CATCHINCR_e0009' , - 'QCFWLT_INCR' , 'CATCHINCR_e0009' , - 'CAPAC_INCR' , 'CATCHINCR_e0009' , - 'CATDEF_INCR' , 'CATCHINCR_e0009' , - 'RZEXC_INCR' , 'CATCHINCR_e0009' , - 'SRFEXC_INCR' , 'CATCHINCR_e0009' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0009' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0009' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0009' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0009' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0009' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0009' , - 'WESNN1_INCR' , 'CATCHINCR_e0009' , - 'WESNN2_INCR' , 'CATCHINCR_e0009' , - 'WESNN3_INCR' , 'CATCHINCR_e0009' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0009' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0009' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0009' , - 'SNDZN1_INCR' , 'CATCHINCR_e0009' , - 'SNDZN2_INCR' , 'CATCHINCR_e0009' , - 'SNDZN3_INCR' , 'CATCHINCR_e0009' , - -:: -catch_progn_incr0010.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0010.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0010.mode: 'instantaneous', -catch_progn_incr0010.frequency: 030000, -catch_progn_incr0010.ref_time: 013000, -catch_progn_incr0010.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0010' , - 'TCFTRN_INCR' , 'CATCHINCR_e0010' , - 'TCFWLT_INCR' , 'CATCHINCR_e0010' , - 'QCFSAT_INCR' , 'CATCHINCR_e0010' , - 'QCFTRN_INCR' , 'CATCHINCR_e0010' , - 'QCFWLT_INCR' , 'CATCHINCR_e0010' , - 'CAPAC_INCR' , 'CATCHINCR_e0010' , - 'CATDEF_INCR' , 'CATCHINCR_e0010' , - 'RZEXC_INCR' , 'CATCHINCR_e0010' , - 'SRFEXC_INCR' , 'CATCHINCR_e0010' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0010' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0010' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0010' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0010' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0010' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0010' , - 'WESNN1_INCR' , 'CATCHINCR_e0010' , - 'WESNN2_INCR' , 'CATCHINCR_e0010' , - 'WESNN3_INCR' , 'CATCHINCR_e0010' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0010' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0010' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0010' , - 'SNDZN1_INCR' , 'CATCHINCR_e0010' , - 'SNDZN2_INCR' , 'CATCHINCR_e0010' , - 'SNDZN3_INCR' , 'CATCHINCR_e0010' , - -:: -catch_progn_incr0011.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0011.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0011.mode: 'instantaneous', -catch_progn_incr0011.frequency: 030000, -catch_progn_incr0011.ref_time: 013000, -catch_progn_incr0011.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0011' , - 'TCFTRN_INCR' , 'CATCHINCR_e0011' , - 'TCFWLT_INCR' , 'CATCHINCR_e0011' , - 'QCFSAT_INCR' , 'CATCHINCR_e0011' , - 'QCFTRN_INCR' , 'CATCHINCR_e0011' , - 'QCFWLT_INCR' , 'CATCHINCR_e0011' , - 'CAPAC_INCR' , 'CATCHINCR_e0011' , - 'CATDEF_INCR' , 'CATCHINCR_e0011' , - 'RZEXC_INCR' , 'CATCHINCR_e0011' , - 'SRFEXC_INCR' , 'CATCHINCR_e0011' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0011' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0011' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0011' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0011' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0011' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0011' , - 'WESNN1_INCR' , 'CATCHINCR_e0011' , - 'WESNN2_INCR' , 'CATCHINCR_e0011' , - 'WESNN3_INCR' , 'CATCHINCR_e0011' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0011' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0011' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0011' , - 'SNDZN1_INCR' , 'CATCHINCR_e0011' , - 'SNDZN2_INCR' , 'CATCHINCR_e0011' , - 'SNDZN3_INCR' , 'CATCHINCR_e0011' , - -:: -catch_progn_incr0012.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0012.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0012.mode: 'instantaneous', -catch_progn_incr0012.frequency: 030000, -catch_progn_incr0012.ref_time: 013000, -catch_progn_incr0012.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0012' , - 'TCFTRN_INCR' , 'CATCHINCR_e0012' , - 'TCFWLT_INCR' , 'CATCHINCR_e0012' , - 'QCFSAT_INCR' , 'CATCHINCR_e0012' , - 'QCFTRN_INCR' , 'CATCHINCR_e0012' , - 'QCFWLT_INCR' , 'CATCHINCR_e0012' , - 'CAPAC_INCR' , 'CATCHINCR_e0012' , - 'CATDEF_INCR' , 'CATCHINCR_e0012' , - 'RZEXC_INCR' , 'CATCHINCR_e0012' , - 'SRFEXC_INCR' , 'CATCHINCR_e0012' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0012' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0012' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0012' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0012' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0012' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0012' , - 'WESNN1_INCR' , 'CATCHINCR_e0012' , - 'WESNN2_INCR' , 'CATCHINCR_e0012' , - 'WESNN3_INCR' , 'CATCHINCR_e0012' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0012' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0012' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0012' , - 'SNDZN1_INCR' , 'CATCHINCR_e0012' , - 'SNDZN2_INCR' , 'CATCHINCR_e0012' , - 'SNDZN3_INCR' , 'CATCHINCR_e0012' , - -:: -catch_progn_incr0013.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0013.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0013.mode: 'instantaneous', -catch_progn_incr0013.frequency: 030000, -catch_progn_incr0013.ref_time: 013000, -catch_progn_incr0013.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0013' , - 'TCFTRN_INCR' , 'CATCHINCR_e0013' , - 'TCFWLT_INCR' , 'CATCHINCR_e0013' , - 'QCFSAT_INCR' , 'CATCHINCR_e0013' , - 'QCFTRN_INCR' , 'CATCHINCR_e0013' , - 'QCFWLT_INCR' , 'CATCHINCR_e0013' , - 'CAPAC_INCR' , 'CATCHINCR_e0013' , - 'CATDEF_INCR' , 'CATCHINCR_e0013' , - 'RZEXC_INCR' , 'CATCHINCR_e0013' , - 'SRFEXC_INCR' , 'CATCHINCR_e0013' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0013' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0013' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0013' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0013' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0013' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0013' , - 'WESNN1_INCR' , 'CATCHINCR_e0013' , - 'WESNN2_INCR' , 'CATCHINCR_e0013' , - 'WESNN3_INCR' , 'CATCHINCR_e0013' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0013' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0013' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0013' , - 'SNDZN1_INCR' , 'CATCHINCR_e0013' , - 'SNDZN2_INCR' , 'CATCHINCR_e0013' , - 'SNDZN3_INCR' , 'CATCHINCR_e0013' , - -:: -catch_progn_incr0014.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0014.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0014.mode: 'instantaneous', -catch_progn_incr0014.frequency: 030000, -catch_progn_incr0014.ref_time: 013000, -catch_progn_incr0014.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0014' , - 'TCFTRN_INCR' , 'CATCHINCR_e0014' , - 'TCFWLT_INCR' , 'CATCHINCR_e0014' , - 'QCFSAT_INCR' , 'CATCHINCR_e0014' , - 'QCFTRN_INCR' , 'CATCHINCR_e0014' , - 'QCFWLT_INCR' , 'CATCHINCR_e0014' , - 'CAPAC_INCR' , 'CATCHINCR_e0014' , - 'CATDEF_INCR' , 'CATCHINCR_e0014' , - 'RZEXC_INCR' , 'CATCHINCR_e0014' , - 'SRFEXC_INCR' , 'CATCHINCR_e0014' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0014' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0014' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0014' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0014' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0014' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0014' , - 'WESNN1_INCR' , 'CATCHINCR_e0014' , - 'WESNN2_INCR' , 'CATCHINCR_e0014' , - 'WESNN3_INCR' , 'CATCHINCR_e0014' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0014' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0014' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0014' , - 'SNDZN1_INCR' , 'CATCHINCR_e0014' , - 'SNDZN2_INCR' , 'CATCHINCR_e0014' , - 'SNDZN3_INCR' , 'CATCHINCR_e0014' , - -:: -catch_progn_incr0015.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0015.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0015.mode: 'instantaneous', -catch_progn_incr0015.frequency: 030000, -catch_progn_incr0015.ref_time: 013000, -catch_progn_incr0015.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0015' , - 'TCFTRN_INCR' , 'CATCHINCR_e0015' , - 'TCFWLT_INCR' , 'CATCHINCR_e0015' , - 'QCFSAT_INCR' , 'CATCHINCR_e0015' , - 'QCFTRN_INCR' , 'CATCHINCR_e0015' , - 'QCFWLT_INCR' , 'CATCHINCR_e0015' , - 'CAPAC_INCR' , 'CATCHINCR_e0015' , - 'CATDEF_INCR' , 'CATCHINCR_e0015' , - 'RZEXC_INCR' , 'CATCHINCR_e0015' , - 'SRFEXC_INCR' , 'CATCHINCR_e0015' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0015' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0015' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0015' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0015' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0015' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0015' , - 'WESNN1_INCR' , 'CATCHINCR_e0015' , - 'WESNN2_INCR' , 'CATCHINCR_e0015' , - 'WESNN3_INCR' , 'CATCHINCR_e0015' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0015' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0015' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0015' , - 'SNDZN1_INCR' , 'CATCHINCR_e0015' , - 'SNDZN2_INCR' , 'CATCHINCR_e0015' , - 'SNDZN3_INCR' , 'CATCHINCR_e0015' , - -:: -catch_progn_incr0016.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0016.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0016.mode: 'instantaneous', -catch_progn_incr0016.frequency: 030000, -catch_progn_incr0016.ref_time: 013000, -catch_progn_incr0016.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0016' , - 'TCFTRN_INCR' , 'CATCHINCR_e0016' , - 'TCFWLT_INCR' , 'CATCHINCR_e0016' , - 'QCFSAT_INCR' , 'CATCHINCR_e0016' , - 'QCFTRN_INCR' , 'CATCHINCR_e0016' , - 'QCFWLT_INCR' , 'CATCHINCR_e0016' , - 'CAPAC_INCR' , 'CATCHINCR_e0016' , - 'CATDEF_INCR' , 'CATCHINCR_e0016' , - 'RZEXC_INCR' , 'CATCHINCR_e0016' , - 'SRFEXC_INCR' , 'CATCHINCR_e0016' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0016' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0016' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0016' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0016' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0016' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0016' , - 'WESNN1_INCR' , 'CATCHINCR_e0016' , - 'WESNN2_INCR' , 'CATCHINCR_e0016' , - 'WESNN3_INCR' , 'CATCHINCR_e0016' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0016' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0016' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0016' , - 'SNDZN1_INCR' , 'CATCHINCR_e0016' , - 'SNDZN2_INCR' , 'CATCHINCR_e0016' , - 'SNDZN3_INCR' , 'CATCHINCR_e0016' , - -:: -catch_progn_incr0017.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0017.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0017.mode: 'instantaneous', -catch_progn_incr0017.frequency: 030000, -catch_progn_incr0017.ref_time: 013000, -catch_progn_incr0017.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0017' , - 'TCFTRN_INCR' , 'CATCHINCR_e0017' , - 'TCFWLT_INCR' , 'CATCHINCR_e0017' , - 'QCFSAT_INCR' , 'CATCHINCR_e0017' , - 'QCFTRN_INCR' , 'CATCHINCR_e0017' , - 'QCFWLT_INCR' , 'CATCHINCR_e0017' , - 'CAPAC_INCR' , 'CATCHINCR_e0017' , - 'CATDEF_INCR' , 'CATCHINCR_e0017' , - 'RZEXC_INCR' , 'CATCHINCR_e0017' , - 'SRFEXC_INCR' , 'CATCHINCR_e0017' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0017' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0017' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0017' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0017' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0017' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0017' , - 'WESNN1_INCR' , 'CATCHINCR_e0017' , - 'WESNN2_INCR' , 'CATCHINCR_e0017' , - 'WESNN3_INCR' , 'CATCHINCR_e0017' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0017' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0017' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0017' , - 'SNDZN1_INCR' , 'CATCHINCR_e0017' , - 'SNDZN2_INCR' , 'CATCHINCR_e0017' , - 'SNDZN3_INCR' , 'CATCHINCR_e0017' , - -:: -catch_progn_incr0018.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0018.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0018.mode: 'instantaneous', -catch_progn_incr0018.frequency: 030000, -catch_progn_incr0018.ref_time: 013000, -catch_progn_incr0018.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0018' , - 'TCFTRN_INCR' , 'CATCHINCR_e0018' , - 'TCFWLT_INCR' , 'CATCHINCR_e0018' , - 'QCFSAT_INCR' , 'CATCHINCR_e0018' , - 'QCFTRN_INCR' , 'CATCHINCR_e0018' , - 'QCFWLT_INCR' , 'CATCHINCR_e0018' , - 'CAPAC_INCR' , 'CATCHINCR_e0018' , - 'CATDEF_INCR' , 'CATCHINCR_e0018' , - 'RZEXC_INCR' , 'CATCHINCR_e0018' , - 'SRFEXC_INCR' , 'CATCHINCR_e0018' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0018' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0018' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0018' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0018' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0018' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0018' , - 'WESNN1_INCR' , 'CATCHINCR_e0018' , - 'WESNN2_INCR' , 'CATCHINCR_e0018' , - 'WESNN3_INCR' , 'CATCHINCR_e0018' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0018' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0018' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0018' , - 'SNDZN1_INCR' , 'CATCHINCR_e0018' , - 'SNDZN2_INCR' , 'CATCHINCR_e0018' , - 'SNDZN3_INCR' , 'CATCHINCR_e0018' , - -:: -catch_progn_incr0019.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0019.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0019.mode: 'instantaneous', -catch_progn_incr0019.frequency: 030000, -catch_progn_incr0019.ref_time: 013000, -catch_progn_incr0019.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0019' , - 'TCFTRN_INCR' , 'CATCHINCR_e0019' , - 'TCFWLT_INCR' , 'CATCHINCR_e0019' , - 'QCFSAT_INCR' , 'CATCHINCR_e0019' , - 'QCFTRN_INCR' , 'CATCHINCR_e0019' , - 'QCFWLT_INCR' , 'CATCHINCR_e0019' , - 'CAPAC_INCR' , 'CATCHINCR_e0019' , - 'CATDEF_INCR' , 'CATCHINCR_e0019' , - 'RZEXC_INCR' , 'CATCHINCR_e0019' , - 'SRFEXC_INCR' , 'CATCHINCR_e0019' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0019' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0019' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0019' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0019' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0019' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0019' , - 'WESNN1_INCR' , 'CATCHINCR_e0019' , - 'WESNN2_INCR' , 'CATCHINCR_e0019' , - 'WESNN3_INCR' , 'CATCHINCR_e0019' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0019' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0019' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0019' , - 'SNDZN1_INCR' , 'CATCHINCR_e0019' , - 'SNDZN2_INCR' , 'CATCHINCR_e0019' , - 'SNDZN3_INCR' , 'CATCHINCR_e0019' , - -:: -catch_progn_incr0020.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0020.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0020.mode: 'instantaneous', -catch_progn_incr0020.frequency: 030000, -catch_progn_incr0020.ref_time: 013000, -catch_progn_incr0020.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0020' , - 'TCFTRN_INCR' , 'CATCHINCR_e0020' , - 'TCFWLT_INCR' , 'CATCHINCR_e0020' , - 'QCFSAT_INCR' , 'CATCHINCR_e0020' , - 'QCFTRN_INCR' , 'CATCHINCR_e0020' , - 'QCFWLT_INCR' , 'CATCHINCR_e0020' , - 'CAPAC_INCR' , 'CATCHINCR_e0020' , - 'CATDEF_INCR' , 'CATCHINCR_e0020' , - 'RZEXC_INCR' , 'CATCHINCR_e0020' , - 'SRFEXC_INCR' , 'CATCHINCR_e0020' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0020' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0020' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0020' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0020' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0020' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0020' , - 'WESNN1_INCR' , 'CATCHINCR_e0020' , - 'WESNN2_INCR' , 'CATCHINCR_e0020' , - 'WESNN3_INCR' , 'CATCHINCR_e0020' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0020' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0020' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0020' , - 'SNDZN1_INCR' , 'CATCHINCR_e0020' , - 'SNDZN2_INCR' , 'CATCHINCR_e0020' , - 'SNDZN3_INCR' , 'CATCHINCR_e0020' , - -:: -catch_progn_incr0021.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0021.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0021.mode: 'instantaneous', -catch_progn_incr0021.frequency: 030000, -catch_progn_incr0021.ref_time: 013000, -catch_progn_incr0021.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0021' , - 'TCFTRN_INCR' , 'CATCHINCR_e0021' , - 'TCFWLT_INCR' , 'CATCHINCR_e0021' , - 'QCFSAT_INCR' , 'CATCHINCR_e0021' , - 'QCFTRN_INCR' , 'CATCHINCR_e0021' , - 'QCFWLT_INCR' , 'CATCHINCR_e0021' , - 'CAPAC_INCR' , 'CATCHINCR_e0021' , - 'CATDEF_INCR' , 'CATCHINCR_e0021' , - 'RZEXC_INCR' , 'CATCHINCR_e0021' , - 'SRFEXC_INCR' , 'CATCHINCR_e0021' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0021' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0021' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0021' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0021' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0021' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0021' , - 'WESNN1_INCR' , 'CATCHINCR_e0021' , - 'WESNN2_INCR' , 'CATCHINCR_e0021' , - 'WESNN3_INCR' , 'CATCHINCR_e0021' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0021' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0021' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0021' , - 'SNDZN1_INCR' , 'CATCHINCR_e0021' , - 'SNDZN2_INCR' , 'CATCHINCR_e0021' , - 'SNDZN3_INCR' , 'CATCHINCR_e0021' , - -:: -catch_progn_incr0022.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0022.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0022.mode: 'instantaneous', -catch_progn_incr0022.frequency: 030000, -catch_progn_incr0022.ref_time: 013000, -catch_progn_incr0022.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0022' , - 'TCFTRN_INCR' , 'CATCHINCR_e0022' , - 'TCFWLT_INCR' , 'CATCHINCR_e0022' , - 'QCFSAT_INCR' , 'CATCHINCR_e0022' , - 'QCFTRN_INCR' , 'CATCHINCR_e0022' , - 'QCFWLT_INCR' , 'CATCHINCR_e0022' , - 'CAPAC_INCR' , 'CATCHINCR_e0022' , - 'CATDEF_INCR' , 'CATCHINCR_e0022' , - 'RZEXC_INCR' , 'CATCHINCR_e0022' , - 'SRFEXC_INCR' , 'CATCHINCR_e0022' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0022' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0022' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0022' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0022' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0022' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0022' , - 'WESNN1_INCR' , 'CATCHINCR_e0022' , - 'WESNN2_INCR' , 'CATCHINCR_e0022' , - 'WESNN3_INCR' , 'CATCHINCR_e0022' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0022' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0022' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0022' , - 'SNDZN1_INCR' , 'CATCHINCR_e0022' , - 'SNDZN2_INCR' , 'CATCHINCR_e0022' , - 'SNDZN3_INCR' , 'CATCHINCR_e0022' , - -:: -catch_progn_incr0023.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0023.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0023.mode: 'instantaneous', -catch_progn_incr0023.frequency: 030000, -catch_progn_incr0023.ref_time: 013000, -catch_progn_incr0023.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0023' , - 'TCFTRN_INCR' , 'CATCHINCR_e0023' , - 'TCFWLT_INCR' , 'CATCHINCR_e0023' , - 'QCFSAT_INCR' , 'CATCHINCR_e0023' , - 'QCFTRN_INCR' , 'CATCHINCR_e0023' , - 'QCFWLT_INCR' , 'CATCHINCR_e0023' , - 'CAPAC_INCR' , 'CATCHINCR_e0023' , - 'CATDEF_INCR' , 'CATCHINCR_e0023' , - 'RZEXC_INCR' , 'CATCHINCR_e0023' , - 'SRFEXC_INCR' , 'CATCHINCR_e0023' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0023' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0023' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0023' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0023' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0023' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0023' , - 'WESNN1_INCR' , 'CATCHINCR_e0023' , - 'WESNN2_INCR' , 'CATCHINCR_e0023' , - 'WESNN3_INCR' , 'CATCHINCR_e0023' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0023' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0023' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0023' , - 'SNDZN1_INCR' , 'CATCHINCR_e0023' , - 'SNDZN2_INCR' , 'CATCHINCR_e0023' , - 'SNDZN3_INCR' , 'CATCHINCR_e0023' , - -:: -catch_progn_incr0024.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0024.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0024.mode: 'instantaneous', -catch_progn_incr0024.frequency: 030000, -catch_progn_incr0024.ref_time: 013000, -catch_progn_incr0024.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0024' , - 'TCFTRN_INCR' , 'CATCHINCR_e0024' , - 'TCFWLT_INCR' , 'CATCHINCR_e0024' , - 'QCFSAT_INCR' , 'CATCHINCR_e0024' , - 'QCFTRN_INCR' , 'CATCHINCR_e0024' , - 'QCFWLT_INCR' , 'CATCHINCR_e0024' , - 'CAPAC_INCR' , 'CATCHINCR_e0024' , - 'CATDEF_INCR' , 'CATCHINCR_e0024' , - 'RZEXC_INCR' , 'CATCHINCR_e0024' , - 'SRFEXC_INCR' , 'CATCHINCR_e0024' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0024' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0024' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0024' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0024' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0024' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0024' , - 'WESNN1_INCR' , 'CATCHINCR_e0024' , - 'WESNN2_INCR' , 'CATCHINCR_e0024' , - 'WESNN3_INCR' , 'CATCHINCR_e0024' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0024' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0024' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0024' , - 'SNDZN1_INCR' , 'CATCHINCR_e0024' , - 'SNDZN2_INCR' , 'CATCHINCR_e0024' , - 'SNDZN3_INCR' , 'CATCHINCR_e0024' , - -:: -catch_progn_incr0025.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0025.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0025.mode: 'instantaneous', -catch_progn_incr0025.frequency: 030000, -catch_progn_incr0025.ref_time: 013000, -catch_progn_incr0025.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0025' , - 'TCFTRN_INCR' , 'CATCHINCR_e0025' , - 'TCFWLT_INCR' , 'CATCHINCR_e0025' , - 'QCFSAT_INCR' , 'CATCHINCR_e0025' , - 'QCFTRN_INCR' , 'CATCHINCR_e0025' , - 'QCFWLT_INCR' , 'CATCHINCR_e0025' , - 'CAPAC_INCR' , 'CATCHINCR_e0025' , - 'CATDEF_INCR' , 'CATCHINCR_e0025' , - 'RZEXC_INCR' , 'CATCHINCR_e0025' , - 'SRFEXC_INCR' , 'CATCHINCR_e0025' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0025' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0025' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0025' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0025' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0025' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0025' , - 'WESNN1_INCR' , 'CATCHINCR_e0025' , - 'WESNN2_INCR' , 'CATCHINCR_e0025' , - 'WESNN3_INCR' , 'CATCHINCR_e0025' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0025' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0025' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0025' , - 'SNDZN1_INCR' , 'CATCHINCR_e0025' , - 'SNDZN2_INCR' , 'CATCHINCR_e0025' , - 'SNDZN3_INCR' , 'CATCHINCR_e0025' , - -:: -catch_progn_incr0026.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0026.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0026.mode: 'instantaneous', -catch_progn_incr0026.frequency: 030000, -catch_progn_incr0026.ref_time: 013000, -catch_progn_incr0026.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0026' , - 'TCFTRN_INCR' , 'CATCHINCR_e0026' , - 'TCFWLT_INCR' , 'CATCHINCR_e0026' , - 'QCFSAT_INCR' , 'CATCHINCR_e0026' , - 'QCFTRN_INCR' , 'CATCHINCR_e0026' , - 'QCFWLT_INCR' , 'CATCHINCR_e0026' , - 'CAPAC_INCR' , 'CATCHINCR_e0026' , - 'CATDEF_INCR' , 'CATCHINCR_e0026' , - 'RZEXC_INCR' , 'CATCHINCR_e0026' , - 'SRFEXC_INCR' , 'CATCHINCR_e0026' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0026' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0026' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0026' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0026' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0026' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0026' , - 'WESNN1_INCR' , 'CATCHINCR_e0026' , - 'WESNN2_INCR' , 'CATCHINCR_e0026' , - 'WESNN3_INCR' , 'CATCHINCR_e0026' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0026' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0026' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0026' , - 'SNDZN1_INCR' , 'CATCHINCR_e0026' , - 'SNDZN2_INCR' , 'CATCHINCR_e0026' , - 'SNDZN3_INCR' , 'CATCHINCR_e0026' , - -:: -catch_progn_incr0027.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0027.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0027.mode: 'instantaneous', -catch_progn_incr0027.frequency: 030000, -catch_progn_incr0027.ref_time: 013000, -catch_progn_incr0027.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0027' , - 'TCFTRN_INCR' , 'CATCHINCR_e0027' , - 'TCFWLT_INCR' , 'CATCHINCR_e0027' , - 'QCFSAT_INCR' , 'CATCHINCR_e0027' , - 'QCFTRN_INCR' , 'CATCHINCR_e0027' , - 'QCFWLT_INCR' , 'CATCHINCR_e0027' , - 'CAPAC_INCR' , 'CATCHINCR_e0027' , - 'CATDEF_INCR' , 'CATCHINCR_e0027' , - 'RZEXC_INCR' , 'CATCHINCR_e0027' , - 'SRFEXC_INCR' , 'CATCHINCR_e0027' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0027' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0027' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0027' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0027' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0027' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0027' , - 'WESNN1_INCR' , 'CATCHINCR_e0027' , - 'WESNN2_INCR' , 'CATCHINCR_e0027' , - 'WESNN3_INCR' , 'CATCHINCR_e0027' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0027' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0027' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0027' , - 'SNDZN1_INCR' , 'CATCHINCR_e0027' , - 'SNDZN2_INCR' , 'CATCHINCR_e0027' , - 'SNDZN3_INCR' , 'CATCHINCR_e0027' , - -:: -catch_progn_incr0028.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0028.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0028.mode: 'instantaneous', -catch_progn_incr0028.frequency: 030000, -catch_progn_incr0028.ref_time: 013000, -catch_progn_incr0028.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0028' , - 'TCFTRN_INCR' , 'CATCHINCR_e0028' , - 'TCFWLT_INCR' , 'CATCHINCR_e0028' , - 'QCFSAT_INCR' , 'CATCHINCR_e0028' , - 'QCFTRN_INCR' , 'CATCHINCR_e0028' , - 'QCFWLT_INCR' , 'CATCHINCR_e0028' , - 'CAPAC_INCR' , 'CATCHINCR_e0028' , - 'CATDEF_INCR' , 'CATCHINCR_e0028' , - 'RZEXC_INCR' , 'CATCHINCR_e0028' , - 'SRFEXC_INCR' , 'CATCHINCR_e0028' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0028' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0028' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0028' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0028' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0028' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0028' , - 'WESNN1_INCR' , 'CATCHINCR_e0028' , - 'WESNN2_INCR' , 'CATCHINCR_e0028' , - 'WESNN3_INCR' , 'CATCHINCR_e0028' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0028' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0028' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0028' , - 'SNDZN1_INCR' , 'CATCHINCR_e0028' , - 'SNDZN2_INCR' , 'CATCHINCR_e0028' , - 'SNDZN3_INCR' , 'CATCHINCR_e0028' , - -:: -catch_progn_incr0029.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0029.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0029.mode: 'instantaneous', -catch_progn_incr0029.frequency: 030000, -catch_progn_incr0029.ref_time: 013000, -catch_progn_incr0029.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0029' , - 'TCFTRN_INCR' , 'CATCHINCR_e0029' , - 'TCFWLT_INCR' , 'CATCHINCR_e0029' , - 'QCFSAT_INCR' , 'CATCHINCR_e0029' , - 'QCFTRN_INCR' , 'CATCHINCR_e0029' , - 'QCFWLT_INCR' , 'CATCHINCR_e0029' , - 'CAPAC_INCR' , 'CATCHINCR_e0029' , - 'CATDEF_INCR' , 'CATCHINCR_e0029' , - 'RZEXC_INCR' , 'CATCHINCR_e0029' , - 'SRFEXC_INCR' , 'CATCHINCR_e0029' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0029' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0029' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0029' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0029' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0029' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0029' , - 'WESNN1_INCR' , 'CATCHINCR_e0029' , - 'WESNN2_INCR' , 'CATCHINCR_e0029' , - 'WESNN3_INCR' , 'CATCHINCR_e0029' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0029' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0029' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0029' , - 'SNDZN1_INCR' , 'CATCHINCR_e0029' , - 'SNDZN2_INCR' , 'CATCHINCR_e0029' , - 'SNDZN3_INCR' , 'CATCHINCR_e0029' , - -:: -catch_progn_incr0030.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0030.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0030.mode: 'instantaneous', -catch_progn_incr0030.frequency: 030000, -catch_progn_incr0030.ref_time: 013000, -catch_progn_incr0030.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0030' , - 'TCFTRN_INCR' , 'CATCHINCR_e0030' , - 'TCFWLT_INCR' , 'CATCHINCR_e0030' , - 'QCFSAT_INCR' , 'CATCHINCR_e0030' , - 'QCFTRN_INCR' , 'CATCHINCR_e0030' , - 'QCFWLT_INCR' , 'CATCHINCR_e0030' , - 'CAPAC_INCR' , 'CATCHINCR_e0030' , - 'CATDEF_INCR' , 'CATCHINCR_e0030' , - 'RZEXC_INCR' , 'CATCHINCR_e0030' , - 'SRFEXC_INCR' , 'CATCHINCR_e0030' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0030' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0030' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0030' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0030' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0030' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0030' , - 'WESNN1_INCR' , 'CATCHINCR_e0030' , - 'WESNN2_INCR' , 'CATCHINCR_e0030' , - 'WESNN3_INCR' , 'CATCHINCR_e0030' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0030' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0030' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0030' , - 'SNDZN1_INCR' , 'CATCHINCR_e0030' , - 'SNDZN2_INCR' , 'CATCHINCR_e0030' , - 'SNDZN3_INCR' , 'CATCHINCR_e0030' , - -:: -catch_progn_incr0031.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0031.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0031.mode: 'instantaneous', -catch_progn_incr0031.frequency: 030000, -catch_progn_incr0031.ref_time: 013000, -catch_progn_incr0031.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0031' , - 'TCFTRN_INCR' , 'CATCHINCR_e0031' , - 'TCFWLT_INCR' , 'CATCHINCR_e0031' , - 'QCFSAT_INCR' , 'CATCHINCR_e0031' , - 'QCFTRN_INCR' , 'CATCHINCR_e0031' , - 'QCFWLT_INCR' , 'CATCHINCR_e0031' , - 'CAPAC_INCR' , 'CATCHINCR_e0031' , - 'CATDEF_INCR' , 'CATCHINCR_e0031' , - 'RZEXC_INCR' , 'CATCHINCR_e0031' , - 'SRFEXC_INCR' , 'CATCHINCR_e0031' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0031' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0031' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0031' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0031' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0031' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0031' , - 'WESNN1_INCR' , 'CATCHINCR_e0031' , - 'WESNN2_INCR' , 'CATCHINCR_e0031' , - 'WESNN3_INCR' , 'CATCHINCR_e0031' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0031' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0031' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0031' , - 'SNDZN1_INCR' , 'CATCHINCR_e0031' , - 'SNDZN2_INCR' , 'CATCHINCR_e0031' , - 'SNDZN3_INCR' , 'CATCHINCR_e0031' , - -:: -catch_progn_incr0032.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', -catch_progn_incr0032.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr0032.mode: 'instantaneous', -catch_progn_incr0032.frequency: 030000, -catch_progn_incr0032.ref_time: 013000, -catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0032' , - 'TCFTRN_INCR' , 'CATCHINCR_e0032' , - 'TCFWLT_INCR' , 'CATCHINCR_e0032' , - 'QCFSAT_INCR' , 'CATCHINCR_e0032' , - 'QCFTRN_INCR' , 'CATCHINCR_e0032' , - 'QCFWLT_INCR' , 'CATCHINCR_e0032' , - 'CAPAC_INCR' , 'CATCHINCR_e0032' , - 'CATDEF_INCR' , 'CATCHINCR_e0032' , - 'RZEXC_INCR' , 'CATCHINCR_e0032' , - 'SRFEXC_INCR' , 'CATCHINCR_e0032' , - 'GHTCNT1_INCR' , 'CATCHINCR_e0032' , - 'GHTCNT2_INCR' , 'CATCHINCR_e0032' , - 'GHTCNT3_INCR' , 'CATCHINCR_e0032' , - 'GHTCNT4_INCR' , 'CATCHINCR_e0032' , - 'GHTCNT5_INCR' , 'CATCHINCR_e0032' , - 'GHTCNT6_INCR' , 'CATCHINCR_e0032' , - 'WESNN1_INCR' , 'CATCHINCR_e0032' , - 'WESNN2_INCR' , 'CATCHINCR_e0032' , - 'WESNN3_INCR' , 'CATCHINCR_e0032' , - 'HTSNNN1_INCR' , 'CATCHINCR_e0032' , - 'HTSNNN2_INCR' , 'CATCHINCR_e0032' , - 'HTSNNN3_INCR' , 'CATCHINCR_e0032' , - 'SNDZN1_INCR' , 'CATCHINCR_e0032' , - 'SNDZN2_INCR' , 'CATCHINCR_e0032' , - 'SNDZN3_INCR' , 'CATCHINCR_e0032' , - -:: diff --git a/GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.central b/GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.central deleted file mode 100644 index 363af785..00000000 --- a/GEOSldas_App/sample_config_files/LADAS/HISTORY.rc.central +++ /dev/null @@ -1,98 +0,0 @@ -# -# Sample GEOSldas HISTORY.rc file for LADAS (central simulation) -# -# This sample is for the GEOSldas instance that is coupled with the central -# simulation component of the Hy4dEnVar ADAS: -# -# (1) The "catch_progn_incr" is output is the ensemble average. -# (2) The "catch_progn_incr" output is in tile space. Its definition is generic -# for any LADAS resolution. -# (3) The resolution of the "lndfcstana" output should be adjusted to match that -# of the LADAS. -# -################################################################################## - -VERSION: 1 -EXPID: MyGEOSldasCentral - -COLLECTIONS: - 'catch_progn_incr' - 'inst3_2d_lndfcstana_Nx' - :: - -GRID_LABELS: PC720x361-DC - PC576x361-DC - :: - -PC720x361-DC.GRID_TYPE: LatLon -PC720x361-DC.IM_WORLD: 720 -PC720x361-DC.JM_WORLD: 361 -PC720x361-DC.POLE: PC -PC720x361-DC.DATELINE: DC -PC720x361-DC.LM: 1 - -PC576x361-DC.GRID_TYPE: LatLon -PC576x361-DC.IM_WORLD: 576 -PC576x361-DC.JM_WORLD: 361 -PC576x361-DC.POLE: PC -PC576x361-DC.DATELINE: DC -PC576x361-DC.LM: 1 - - -catch_progn_incr.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble-Average Land Prognostics Increments', -catch_progn_incr.template: '%y4%m2%d2_%h2%n2z.bin', -catch_progn_incr.mode: 'instantaneous', -catch_progn_incr.frequency: 030000, -catch_progn_incr.ref_time: 013000, -catch_progn_incr.fields: 'TCFSAT_INCR' , 'LANDASSIM' , - 'TCFTRN_INCR' , 'LANDASSIM' , - 'TCFWLT_INCR' , 'LANDASSIM' , - 'QCFSAT_INCR' , 'LANDASSIM' , - 'QCFTRN_INCR' , 'LANDASSIM' , - 'QCFWLT_INCR' , 'LANDASSIM' , - 'CAPAC_INCR' , 'LANDASSIM' , - 'CATDEF_INCR' , 'LANDASSIM' , - 'RZEXC_INCR' , 'LANDASSIM' , - 'SRFEXC_INCR' , 'LANDASSIM' , - 'GHTCNT1_INCR' , 'LANDASSIM' , - 'GHTCNT2_INCR' , 'LANDASSIM' , - 'GHTCNT3_INCR' , 'LANDASSIM' , - 'GHTCNT4_INCR' , 'LANDASSIM' , - 'GHTCNT5_INCR' , 'LANDASSIM' , - 'GHTCNT6_INCR' , 'LANDASSIM' , - 'WESNN1_INCR' , 'LANDASSIM' , - 'WESNN2_INCR' , 'LANDASSIM' , - 'WESNN3_INCR' , 'LANDASSIM' , - 'HTSNNN1_INCR' , 'LANDASSIM' , - 'HTSNNN2_INCR' , 'LANDASSIM' , - 'HTSNNN3_INCR' , 'LANDASSIM' , - 'SNDZN1_INCR' , 'LANDASSIM' , - 'SNDZN2_INCR' , 'LANDASSIM' , - 'SNDZN3_INCR' , 'LANDASSIM' , - :: - - -inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble-Average Land Forecast and Analysis Diagnostics', -inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', -inst3_2d_lndfcstana_Nx.archive: '%c/Y%y4', -inst3_2d_lndfcstana_Nx.mode: 'instantaneous', -inst3_2d_lndfcstana_Nx.frequency: 030000, -inst3_2d_lndfcstana_Nx.ref_time: 013000, -inst3_2d_lndfcstana_Nx.format: 'CFIO', -inst3_2d_lndfcstana_Nx.regrid_exch: '../input/tile.data', -inst3_2d_lndfcstana_Nx.regrid_name: 'PE180x1080-CF', -inst3_2d_lndfcstana_Nx.grid_label: PC576x361-DC, -inst3_2d_lndfcstana_Nx.deflate: 2, -inst3_2d_lndfcstana_Nx.fields: 'WCSF' , 'ENSAVG' , 'SFMC_FCST' , - 'WCRZ' , 'ENSAVG' , 'RZMC_FCST' , - 'WCPR' , 'ENSAVG' , 'PRMC_FCST' , - 'TPSURF' , 'ENSAVG' , 'TSURF_FCST' , - 'TSOIL1TILE' , 'ENSAVG' , 'TSOIL1_FCST' , - 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , - 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , - 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , - 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , - 'TSOIL1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , - :: - -# ========================== EOF ============================================================== diff --git a/GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas b/GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas new file mode 100644 index 00000000..4ba42f99 --- /dev/null +++ b/GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas @@ -0,0 +1,39 @@ +# +# README on GEOSldas "exeinp" file for LADAS +# +# for the GEOSldas instance that is coupled with +# Hy4dEnVar ADAS: +# +# (1) Create exeinp template using: +# ldas_setup sample --exeinp > ldas_exeinp.txt +# +# (2) Use the resource parameter settings below when editing ldas_exeinp.txt +# +# (3) The following resource parameters are provided via fvsetup, +# which supersede the default in ldas_exeinp.txt +# EXP_ID +# EXP_DOMAIN +# BEG_DATE +# RESTART_ID +# RESTART_PATH +# RESTART_DOMAIN +# MET_TAG +# MET_PATH +# bcs_version in BCS_PATH +# BCS_RESOLUTION +# LADAS_COUPLING +# ADAS_EXPDIR +# GID +# +# (4) The following resource parameters are hard-wired for ladas +# which supersede the default in ldas_exeinp.txt +# MET_HINTERP +# LANDASSIM_DT +# LANDASSIM_T0 +# FIRST_ENS_ID +# ENSEMBLE_FORCING +# JOB_SGMT +# NUM_SGMT +# NUM_LDAS_ENSEMBLE is hard-wired as 32 if coupled with atmens +############################################################################## + diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens deleted file mode 100644 index 410505dd..00000000 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens +++ /dev/null @@ -1,48 +0,0 @@ -# -# Sample GEOSldas "exeinp" file for LADAS (atm ensemble) -# -# This sample is for the GEOSldas instance that is coupled with the atmospheric -# ensemble component of the Hy4dEnVar ADAS: -# -# (1) Create exeinp template using: -# ldas_setup sample --exeinp > MY_exeinp.txt -# -# (2) Use the resource parameter settings below when editing MY_exeinp.txt -# -# (3) The following resource parameters are provided via fvsetup, -# which supersede the default in MY_exeinp.txt: -# ADAS_EXPDIR -# ADAS_EXPID -# EXP_ID -# MET_TAG -# BEG_DATE -# GID -############################################################################## - -# e.g., ATMENS_AGCM_GRID = CF0090x6C -EXP_DOMAIN: [ATMENS_AGCM_GRID]_GLOBAL - -NUM_LDAS_ENSEMBLE: [NUM_ATMENS_ENSEMBLE] - -LADAS_COUPLING: 2 - -ADAS_EXPDIR: [full_path]/[ADAS_EXPID] - -MET_TAG: [ADAS_EXPID]__bkg -MET_PATH: [ADAS_EXPDIR]/atmens/mem - -MET_HINTERP: 0 - -LAND_ASSIM: YES - -LANDASSIM_DT: 10800 -LANDASSIM_T0: 013000 - -FIRST_ENS_ID: 1 - -ENSEMBLE_FORCING: YES - -JOB_SGMT: 00000000 060000 -NUM_SGMT: 1 - -################################# EOF ######################################## diff --git a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central deleted file mode 100644 index 0c682821..00000000 --- a/GEOSldas_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ /dev/null @@ -1,50 +0,0 @@ -# -# Sample GEOSldas "exeinp" file for LADAS (central simulation) -# -# This sample is for the GEOSldas instance that is coupled with the central -# simulation component of the Hy4dEnVar ADAS: -# -# (1) Create exeinp template using: -# ldas_setup sample --exeinp > MY_exeinp.txt -# -# (2) Use the resource parameter settings below when editing MY_exeinp.txt -# -# (3) The following resource parameters are provided via fvsetup, -# which supersede the default in MY_exeinp.txt -# ADAS_EXPDIR -# ADAS_EXPID -# EXP_ID -# MET_TAG -# BEG_DATE -# GID -############################################################################## - -# e.g., CENTRAL_AGCM_GRID = CF0360x6C -EXP_DOMAIN: [CENTRAL_AGCM_GRID]_GLOBAL - -LADAS_COUPLING: 1 - -ADAS_EXPDIR: [full_path]/[ADAS_EXPID] - -MET_TAG: [ADAS_EXPID]__bkg -MET_PATH: ../../../../recycle/holdpredout -# option to use perturbed forcing created from central simulation and atm ensemble -# MET_PATH: [ADAS_EXPDIR]/atmens/rgdlfo - -MET_HINTERP: 0 - -LAND_ASSIM: YES - -LANDASSIM_DT: 10800 -LANDASSIM_T0: 013000 - -FIRST_ENS_ID: 1 - -ENSEMBLE_FORCING: NO -# option to use perturbed forcing created from central simulation and atm ensemble -# ENSEMBLE_FORCING: YES - -JOB_SGMT: 00000000 060000 -NUM_SGMT: 1 - -################################# EOF ######################################## From 01f0f63c2d0d2429b5b7cf4ea53620441cccacd6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Wed, 7 May 2025 10:57:24 -0400 Subject: [PATCH 09/36] minor cleanup as suggested by Weiyuan (ldas_setup) Co-authored-by: Weiyuan Jiang <52509753+weiyuan-jiang@users.noreply.github.com> --- GEOSldas_App/ldas_setup | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 22c14376..ecbcd15c 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -158,13 +158,13 @@ class LDASsetup: for key in rqdExeInpKeys : assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) - if cmdLineArgs['nymdb'] != 'None' and cmdLineArgs['nhmsb'] != 'None' : + if self.nymdb != 'None' and self.nhmsb != 'None' : self.date = f"{self.nymdb} {self.nhmsb}" self.rqdExeInp[ 'BEG_DATE' ] = self.date - if cmdLineArgs['ladas_cpl'] != 'None' : + if self.ladas_cpl != 'None' : self.rqdExeInp['LADAS_COUPLING'] = self.ladas_cpl - if cmdLineArgs['rstloc'] != 'None' : - rstloc_ = cmdLineArgs['rstloc'].rstrip('/') # remove trailing '/' + if self.rstloc != 'None' : + rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' assert os.path.isdir(rstloc_) # ldas exp for rs should exist self.rstloc = os.path.abspath(rstloc_) From f07f2e4a388dd02e512897ca4eeddfe26409e9a5 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 7 May 2025 11:31:05 -0400 Subject: [PATCH 10/36] additional cleanup as suggested by Weiyuan for integrated land-atm DAS setup (ldas_setup) --- GEOSldas_App/ldas_setup | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index ecbcd15c..02a68b92 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -158,15 +158,17 @@ class LDASsetup: for key in rqdExeInpKeys : assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) + # process command line args that may be useful independent of the value of LADAS_COUPLING if self.nymdb != 'None' and self.nhmsb != 'None' : - self.date = f"{self.nymdb} {self.nhmsb}" - self.rqdExeInp[ 'BEG_DATE' ] = self.date + self.rqdExeInp['BEG_DATE'] = f"{self.nymdb} {self.nhmsb}" if self.ladas_cpl != 'None' : self.rqdExeInp['LADAS_COUPLING'] = self.ladas_cpl if self.rstloc != 'None' : - rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' - assert os.path.isdir(rstloc_) # ldas exp for rs should exist + rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' + assert os.path.isdir(rstloc_) # make sure rstloc_ is a valid directory self.rstloc = os.path.abspath(rstloc_) + self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) + self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) # print rqd exe inputs if self.verbose: @@ -185,7 +187,7 @@ class LDASsetup: self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) self.adas_expdir = '' if self.ladas_coupling > 0 : - self.adas_expdir = os.path.dirname(self.exphome) + self.adas_expdir = os.path.dirname( self.exphome) self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' @@ -208,14 +210,14 @@ class LDASsetup: self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' # when coupled to ADAS, "BCS_PATH" in exeinp file must EXCLUDE bcs version info - uptotiles = os.path.dirname(self.rqdExeInp['BCS_PATH'].rstrip('/')) - self.rqdExeInp['BCS_PATH'] = uptotiles + '/' + self.bcs_version + tmppath_ = os.path.dirname(self.rqdExeInp['BCS_PATH'].rstrip('/')) + assert os.path.isdir(tmppath_) + self.rqdExeInp['BCS_PATH'] = tmppath_ + '/' + self.bcs_version if self.bcs_version == "Icarus-NLv3" : self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' - self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' - self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) - self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) + self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + # the following are not in default rqdExeInp list self.rqdExeInp['MET_HINTERP'] = 0 self.rqdExeInp['LANDASSIM_DT'] = "10800" From 0ec5846c7842bf8058a8a2c59f7108477a045bce Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 7 May 2025 11:54:25 -0400 Subject: [PATCH 11/36] change handling of BCS_PATH in setup of coupled land-atm DAS (ldas_setup) --- GEOSldas_App/ldas_setup | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 02a68b92..59a71e72 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -210,9 +210,7 @@ class LDASsetup: self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' # when coupled to ADAS, "BCS_PATH" in exeinp file must EXCLUDE bcs version info - tmppath_ = os.path.dirname(self.rqdExeInp['BCS_PATH'].rstrip('/')) - assert os.path.isdir(tmppath_) - self.rqdExeInp['BCS_PATH'] = tmppath_ + '/' + self.bcs_version + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'].rstrip('/') + '/' + self.bcs_version if self.bcs_version == "Icarus-NLv3" : self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' From ab9c3c39a7c875102d1cc30323f25ac15cda3e63 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 7 May 2025 12:53:55 -0400 Subject: [PATCH 12/36] exclude AGCM defaults of GEOS_SurfaceGridComp.rc from sample exeinp file (ldas_setup) --- GEOSldas_App/ldas_setup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 59a71e72..ddc13c42 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1668,6 +1668,9 @@ def _printExeInputKeys(rqdExeInpKeys): if ( 5<=i_ and i_<=21) : # ignore lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited i_ +=1 continue + if 'GEOSagcm=>' in line: # ignore lines with defaults for GEOSagcm + i_ +=1 + continue if '"GEOSldas=>"' in line: sys.stdout.write(line) elif 'GEOSldas=>' in line: From ea03973366d8a67dddce28421352fad00ef08ef6 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 13 May 2025 11:04:06 -0400 Subject: [PATCH 13/36] further changes in setting exeinp & batinp variables --- GEOSldas_App/ldas_setup | 208 +++++++++++++++---------------- GEOSldas_App/lenkf_j_template.py | 10 ++ 2 files changed, 111 insertions(+), 107 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index ddc13c42..af329dd7 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -70,9 +70,14 @@ class LDASsetup: # sample sub-command # by construction, we can have # either: {'exeinp': False, 'batinp': True } - # or: {'exeinp': True, 'batinp': False} + # or: {'exeinp': True, 'batinp': False} + if cmdLineArgs['ladas_cpl'] != 'None' : + ladas_cpl = int(cmdLineArgs['ladas_cpl']) if cmdLineArgs['exeinp']: - _printExeInputKeys(rqdExeInpKeys) + if ladas_cpl > 0: + _printExeInputKeys(rqdExeInpKeys,ladas_cpl) + else : + _printExeInputKeys(rqdExeInpKeys) elif cmdLineArgs['batinp']: _printRmInputKeys(rqdRmInpKeys, optSlurmInpKeys) else: @@ -139,7 +144,7 @@ class LDASsetup: self.rqdExeInp = self._parseInputFile(cmdLineArgs['exeinpfile']) # verifing the required input if 'RESTART' not in self.rqdExeInp : - self.rqdExeInp['RESTART'] = 1 + self.rqdExeInp['RESTART'] = "1" if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) ==0 : @@ -155,14 +160,11 @@ class LDASsetup: self.rqdExeInp['RESTART_ID'] = "none" self.rqdExeInp['RESTART_DOMAIN'] = "none" self.rqdExeInp['RESTART_PATH'] = "none" - - for key in rqdExeInpKeys : - assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) # process command line args that may be useful independent of the value of LADAS_COUPLING if self.nymdb != 'None' and self.nhmsb != 'None' : self.rqdExeInp['BEG_DATE'] = f"{self.nymdb} {self.nhmsb}" if self.ladas_cpl != 'None' : - self.rqdExeInp['LADAS_COUPLING'] = self.ladas_cpl + self.ladas_coupling = int(self.ladas_cpl) if self.rstloc != 'None' : rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' assert os.path.isdir(rstloc_) # make sure rstloc_ is a valid directory @@ -170,21 +172,7 @@ class LDASsetup: self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) - # print rqd exe inputs - if self.verbose: - print ('\nInputs from execfile:\n') - _printdict(self.rqdExeInp) - - # nens is an integer and =1 for model run - 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 - self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) - ### check if ldas is coupled to adas; if so, set/overwrite input parameters accordingly - self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) self.adas_expdir = '' if self.ladas_coupling > 0 : self.adas_expdir = os.path.dirname( self.exphome) @@ -196,6 +184,7 @@ class LDASsetup: self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' + self.nens = 24 #for now hardwire nens for atm det elif self.ladas_coupling == 2 : # ldas coupled with ensemble component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' @@ -208,8 +197,10 @@ class LDASsetup: self.first_ens_id = 1 self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' - - # when coupled to ADAS, "BCS_PATH" in exeinp file must EXCLUDE bcs version info + + # when coupled to ADAS, "BCS_PATH" EXCLUDE bcs version info + # hard-wired BCS_PATH for now + self.rqdExeInp['BCS_PATH'] = "/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles" self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'].rstrip('/') + '/' + self.bcs_version if self.bcs_version == "Icarus-NLv3" : self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' @@ -217,13 +208,39 @@ class LDASsetup: self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' # the following are not in default rqdExeInp list + self.rqdExeInp['LAND_ASSIM'] = "YES" self.rqdExeInp['MET_HINTERP'] = 0 self.rqdExeInp['LANDASSIM_DT'] = "10800" self.rqdExeInp['LANDASSIM_T0'] = "013000" self.rqdExeInp['JOB_SGMT'] = "00000000 060000" - self.rqdExeInp['NUM_SGMT'] = 1 - ### - + self.rqdExeInp['NUM_SGMT'] = 1 + self.rqdExeInp['FORCE_DTSTEP'] = 3600 + + dt_str = f"{self.nymdb} {self.nhmsb}" + dt = datetime.strptime(dt_str, "%Y%m%d %H%M%S") + dt_new = dt + timedelta(hours=6) + dt_str_new = dt_new.strftime("%Y%m%d %H%M%S") + self.rqdExeInp['END_DATE'] = dt_str_new + self.rqdExeInp['NML_INPUT_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/SPECnml/" + self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" + #### + + for key in rqdExeInpKeys : + assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) + + # print rqd exe inputs + if self.verbose: + print ('\nInputs from execfile:\n') + _printdict(self.rqdExeInp) + + # nens is an integer and =1 for model run + 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 + self.first_ens_id = int(self.rqdExeInp.get('FIRST_ENS_ID',0)) + self.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0)) if self.nens > 1: self.perturb = 1 @@ -402,9 +419,6 @@ class LDASsetup: if 'POSTPROC_HIST' not in self.rqdExeInp: self.rqdExeInp['POSTPROC_HIST'] = 0 - if 'LADAS_COUPLING' not in self.rqdExeInp: - self.rqdExeInp['LADAS_COUPLING'] = 0 - if 'RUN_IRRIG' not in self.rqdExeInp: self.rqdExeInp['RUN_IRRIG'] = 0 @@ -511,21 +525,28 @@ class LDASsetup: inpDictFromFile = self._parseInputFile(cmdLineArgs['batinpfile']) - # REQUIRED inputs - for key in rqdRmInpKeys: - self.rqdRmInp[key] = inpDictFromFile.pop(key) - - # checks on rqd rm inputs - ## account and walltime should exist - assert self.rqdRmInp['account'] - if cmdLineArgs['account'] != 'None': - self.rqdRmInp['account'] = cmdLineArgs['account'] - assert self.rqdRmInp['walltime'] - ## ntasks_model is a +ve integer - _ntasks = int(self.rqdRmInp['ntasks_model']) - assert _ntasks>0 - self.rqdRmInp['ntasks_model'] = _ntasks - _ntasks = None + if self.ladas_coupling > 0 : + if cmdLineArgs['account'] != 'None': + self.rqdRmInp['account'] = cmdLineArgs['account'] + self.rqdRmInp['walltime'] = "00:30:00" + self.rqdRmInp['ntasks_model'] = 120 + self.rqdRmInp['ntasks-per-node'] = 60 + else : + # REQUIRED inputs + for key in rqdRmInpKeys: + self.rqdRmInp[key] = inpDictFromFile.pop(key) + + # checks on rqd rm inputs + ## account and walltime should exist + assert self.rqdRmInp['account'] + if cmdLineArgs['account'] != 'None': + self.rqdRmInp['account'] = cmdLineArgs['account'] + assert self.rqdRmInp['walltime'] + ## ntasks_model is a +ve integer + _ntasks = int(self.rqdRmInp['ntasks_model']) + assert _ntasks>0 + self.rqdRmInp['ntasks_model'] = _ntasks + _ntasks = None # print rqd rm inputs if self.verbose: @@ -1477,11 +1498,11 @@ def _printdict(d): for key, val in d.items(): print (key.ljust(23), ':', val) -def _printExeInputKeys(rqdExeInpKeys): +def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): """ Private method: print sample exe input """ - + print ('####################################################################################') print ('# #') print ('# REQUIRED INPUTS #') @@ -1489,7 +1510,8 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# These inputs are needed to set up output dir structure. #') print ('# #') print ('####################################################################################') - print () + print () + print ('############################################################') print ('# #') print ('# EXPERIMENT INFO #') @@ -1599,54 +1621,6 @@ def _printExeInputKeys(rqdExeInpKeys): print ('BCS_RESOLUTION:') print () print ('############################################################') - print ('# #') - print ('# LADAS COUPLING #') - print ('# #') - print ('# Coupling of LDAS to ADAS ("LADAS"): #') - print ('# #') - print ('# 0 -- LDAS not coupled with ADAS (default) #') - print ('# 1 -- LDAS coupled with central (det) member of ADAS #') - print ('# 2 -- LDAS coupled with ens component of ADAS #') - print ('# #') - print ('# Requirements for LADAS_COUPLING > 0 are as follows, #') - print ('# with most requirements hardwired into ldas_setup: #') - print ('# #') - print ('# (0) ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') - print ('# #') - print ('# (1) BEG_DATE must be consistent with first cycle date #') - print ('# and time of ADAS experiment (time is typically #') - print ('# 3z, 9z, 15z, or 21z) #') - print ('# #') - print ('# (2) EXP_DOMAIN must be global CS grid as in ADAS exp #') - print ('# #') - print ('# (3) MET_TAG must be set to [ADAS_EXPID]__bkg #') - print ('# MET_PATH must be set as follows for #') - print ('# LADAS_COUPLING = 1: #') - print ('# ../../../../recycle/holdpredout/ #') - print ('# LADAS_COUPLING = 2: #') - print ('# [ADAS_EXPDIR]/atmens/mem #') - print ('# #') - print ('# (4) BCS_PATH must be consistent with that of #') - print ('# [ADAS_EXPDIR][/run/lnbcs #') - print ('# #') - print ('# (5) JOB_SGMT must match ADAS analysis window #') - print ('# (typically 6h) #') - print ('# #') - print ('# (6) NUM_SGMT must be set to 1 #') - print ('# #') - print ('# (7) HISTORY: #') - print ('# - instantaneous "catch_progn_incr" must be in #') - print ('# HISTORY collection #') - print ('# - time step must be consistent with that of #') - print ('# LDAS analysis #') - print ('# - for LADAS_COUPLING=2, HISTORY must include #') - print ('# "catch_progn_incr[ENS_INDEX]" #') - print ('# #') - print ('############################################################') - print () - print ('LADAS_COUPLING: 0') - print () - print () _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory @@ -1668,18 +1642,32 @@ def _printExeInputKeys(rqdExeInpKeys): if ( 5<=i_ and i_<=21) : # ignore lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited i_ +=1 continue - if 'GEOSagcm=>' in line: # ignore lines with defaults for GEOSagcm - i_ +=1 - continue - if '"GEOSldas=>"' in line: - sys.stdout.write(line) - elif 'GEOSldas=>' in line: - line0 = line.split("GEOSldas=>")[1] - sys.stdout.write(line0) - elif not line.strip() or line.strip().startswith('#'): - sys.stdout.write(line) - sys.stdout.flush() - i_ += 1 + if ladas_cpl > 0 : + if 'GEOSldas=>' in line: # ignore lines with defaults for GEOSldas + i_ +=1 + continue + if '"GEOSagcm=>"' in line: + sys.stdout.write(line) + elif 'GEOSagcm=>' in line: + line0 = line.split("GEOSagcm=>")[1] + sys.stdout.write(line0) + elif not line.strip() or line.strip().startswith('#'): + sys.stdout.write(line) + sys.stdout.flush() + i_ += 1 + else : + if 'GEOSagcm=>' in line: # ignore lines with defaults for GEOSagcm + i_ +=1 + continue + if '"GEOSldas=>"' in line: + sys.stdout.write(line) + elif 'GEOSldas=>' in line: + line0 = line.split("GEOSldas=>")[1] + sys.stdout.write(line0) + elif not line.strip() or line.strip().startswith('#'): + sys.stdout.write(line) + sys.stdout.flush() + i_ += 1 print () print () @@ -1750,6 +1738,12 @@ def parseCmdLine(): help='print sample input file for the resource manager (SLURM)', action='store_true', ) + p_sample.add_argument( + '--ladas_cpl', + help='land-atm DAS coupling mode: LDAS coupled with ADAS' , + type=str, default='None' + ) + # subparser: setup command p_setup = p_sub.add_parser( 'setup', diff --git a/GEOSldas_App/lenkf_j_template.py b/GEOSldas_App/lenkf_j_template.py index 6dcee191..85292b63 100644 --- a/GEOSldas_App/lenkf_j_template.py +++ b/GEOSldas_App/lenkf_j_template.py @@ -856,6 +856,16 @@ if ( $LADAS_COUPLING > 0 ) then if ( $rc == 0 ) then + ##update CAP.rc END_DATE in $HOMDIR/ + set date = `$GEOSBIN/tick $nymdf $nhmsf $dt` + set nymdend = $date[1] + set nhmsend = $date[2] + cd $HOMDIR + set oldstring = `cat CAP.rc | grep END_DATE:` + set newstring = "END_DATE: $nymdend $nhmsend" + /bin/mv CAP.rc CAP.tmp + cat CAP.tmp | sed -e "s?$oldstring?$newstring?g" > CAP.rc + /bin/rm -f CAP.tmp echo 'SUCCEEDED' > $HOMDIR/lenkf_job_completed.txt endif else From 11dca4510f125627473468fff8e5ec22aa98d09f Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 13 May 2025 13:51:26 -0400 Subject: [PATCH 14/36] minor cleanup to improve readability (ldas_setup) --- GEOSldas_App/ldas_setup | 61 ++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index af329dd7..d0d2a46a 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -13,20 +13,21 @@ import resource import subprocess as sp import shlex import tempfile -from dateutil import rrule -from datetime import datetime -from datetime import timedelta -from collections import OrderedDict + +from dateutil import rrule +from datetime import datetime +from datetime import timedelta +from collections import OrderedDict from dateutil.relativedelta import relativedelta -from remap_utils import * -from remap_catchANDcn import * -from lenkf_j_template import * +from remap_utils import * +from remap_catchANDcn import * +from lenkf_j_template import * + """ This script is intended to be run from any installed directory with GEOSldas.x and ldas_setup (The default setup is ../install/bin) """ - class LDASsetup: def __init__(self, cmdLineArgs): @@ -52,7 +53,7 @@ class LDASsetup: 'ADAS_EXPDIR', 'BCS_RESOLUTION' ] - self.GEOS_SITE = "@GEOS_SITE@" + self.GEOS_SITE = "@GEOS_SITE@" # ------ # Required resource manager input fields @@ -73,7 +74,7 @@ class LDASsetup: # or: {'exeinp': True, 'batinp': False} if cmdLineArgs['ladas_cpl'] != 'None' : ladas_cpl = int(cmdLineArgs['ladas_cpl']) - if cmdLineArgs['exeinp']: + if cmdLineArgs['exeinp']: if ladas_cpl > 0: _printExeInputKeys(rqdExeInpKeys,ladas_cpl) else : @@ -609,7 +610,8 @@ class LDASsetup: else: self.optRmInp['writers-per-node'] = 0 - + # ----------------------------------------------------------------------------------- + def _parseInputFile(self, inpfile): """ Private method: parse input file and return a dict of options @@ -657,7 +659,8 @@ class LDASsetup: return inpdict - + # ----------------------------------------------------------------------------------- + def _mkdir_p(self,path): """ Private method: implement 'mkdir -p' functionality @@ -668,6 +671,8 @@ class LDASsetup: else: os.makedirs(path) + # ----------------------------------------------------------------------------------- + def createDirStructure(self): """ Create required dir structure @@ -733,6 +738,8 @@ class LDASsetup: status = True return status + # ----------------------------------------------------------------------------------- + # create links to BCs, restarts, met forcing, ... def createLnRstBc(self) : # link bld dir @@ -1078,6 +1085,8 @@ class LDASsetup: status = True return status + # ----------------------------------------------------------------------------------- + def createRCFiles(self): """ (1) get resource files form DEFAULT rc files from /etc @@ -1346,6 +1355,8 @@ class LDASsetup: status=True return status + # ----------------------------------------------------------------------------------- + def createBatchRun(self): """ """ @@ -1401,7 +1412,8 @@ class LDASsetup: status = True return status - + # ----------------------------------------------------------------------------------- + def createRunScripts(self): """ """ @@ -1490,6 +1502,8 @@ class LDASsetup: status = True return status +# ----------------------------------------------------------------------------------- + def _printdict(d): """ Private method: print a 'flat' dictionary @@ -1498,6 +1512,8 @@ def _printdict(d): for key, val in d.items(): print (key.ljust(23), ':', val) +# ----------------------------------------------------------------------------------- + def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): """ Private method: print sample exe input @@ -1671,6 +1687,8 @@ def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): print () print () +# ----------------------------------------------------------------------------------- + def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): """ Private method: print sample resource manager input @@ -1695,8 +1713,8 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('# OPTIONAL inputs') print ('#') print ('# NOTE:') - print ('# - job_name = name of experiment; default is "exp_id"') - print ('# - qos = quality-of-service; do not specify by default; specify "debug" for faster but limited service.') + print ('# - job_name = name of experiment; default is "exp_id"') + print ('# - qos = quality-of-service; do not specify by default; specify "debug" for faster but limited service.') print ('# - oserver_nodes = number of nodes for oserver ( default is 0 )') print ('# - writers-per-node = tasks per oserver_node for writing ( default is 5 ),') print ('# IMPORTANT REQUIREMENT: total #writers = writers-per-node * oserver_nodes >= 2') @@ -1705,6 +1723,8 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): for key in optRmInpKeys: print ('#'+key + ':') +# ----------------------------------------------------------------------------------- + def parseCmdLine(): """ parse command line arguments and return a dict of options @@ -1840,17 +1860,20 @@ if __name__=='__main__': status = ld.createDirStructure() assert(status) - print ("creating restart and bc") + print ("creating links to restarts, BCs, met forcing, ...") status = ld.createLnRstBc() assert(status) print ("creating RC Files") - status =ld.createRCFiles() - assert status + status = ld.createRCFiles() + assert(status) print ("creating gcm style batch Run scripts lenkf.j") status = ld.createRunScripts() - + assert(status) + print ("creating batch Run scripts") status = ld.createBatchRun() assert (status) + +# =================== EOF ======================================================================= From 7f115d9f865c24312f11712cf4e99087b6b156d8 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 13 May 2025 16:51:14 -0400 Subject: [PATCH 15/36] additional changes and cleanup for integrated land-atm DAS config (ldas_setup): - cleaned up "ladas_cpl" variable names and processing - connected END_DATE to JOB_SGMT - for ladas_cpl>0 - for now, changed default n-tasks-per-node to 46 so it works with Cascade Lake - exclude unnecessary "required exe inputs" from sample file - simplified processing of model parameter defaults from GEOS_SurfaceGridComp.rc - edited comments - white space changes --- GEOSldas_App/ldas_setup | 418 +++++++++++++++++++++------------------- 1 file changed, 218 insertions(+), 200 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index d0d2a46a..35f9e8cb 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -64,6 +64,11 @@ class LDASsetup: # ------ optSlurmInpKeys = ['job_name', 'qos', 'oserver_nodes', 'writers-per-node'] + # determine if LDAS should be coupled with ADAS + self.ladas_cpl = 0 # default is stand-alone (offline) LDAS + if cmdLineArgs['ladas_cpl'] != 'None' : + self.ladas_cpl = int(cmdLineArgs['ladas_cpl']) + # ------ # ./ldsetup.py sample ... # ------ @@ -72,15 +77,10 @@ class LDASsetup: # by construction, we can have # either: {'exeinp': False, 'batinp': True } # or: {'exeinp': True, 'batinp': False} - if cmdLineArgs['ladas_cpl'] != 'None' : - ladas_cpl = int(cmdLineArgs['ladas_cpl']) - if cmdLineArgs['exeinp']: - if ladas_cpl > 0: - _printExeInputKeys(rqdExeInpKeys,ladas_cpl) - else : - _printExeInputKeys(rqdExeInpKeys) + if cmdLineArgs['exeinp']: + _printExeInputKeys(rqdExeInpKeys, self.ladas_cpl) elif cmdLineArgs['batinp']: - _printRmInputKeys(rqdRmInpKeys, optSlurmInpKeys) + _printRmInputKeys( rqdRmInpKeys, optSlurmInpKeys) else: raise Exception('unrecognized option') sys.exit(0) @@ -101,7 +101,6 @@ class LDASsetup: self.nhmsb = cmdLineArgs['nhmsb'] self.agcm_res = cmdLineArgs['agcm_res'] self.bcs_version = cmdLineArgs['bcs_version'] - self.ladas_cpl = cmdLineArgs['ladas_cpl'] self.rstloc = cmdLineArgs['rstloc'] # obsolete command line args @@ -131,7 +130,6 @@ class LDASsetup: self.nSegments = 1 self.perturb = 0 self.first_ens_id = 0 - self.ladas_coupling = 0 self.in_rstfile = None self.in_tilefile = 'None' # default string self.ens_id_width = 6 # _eXXXX @@ -161,11 +159,9 @@ class LDASsetup: self.rqdExeInp['RESTART_ID'] = "none" self.rqdExeInp['RESTART_DOMAIN'] = "none" self.rqdExeInp['RESTART_PATH'] = "none" - # process command line args that may be useful independent of the value of LADAS_COUPLING + # process command line args that may be useful independent of the value of self.ladas_cpl if self.nymdb != 'None' and self.nhmsb != 'None' : self.rqdExeInp['BEG_DATE'] = f"{self.nymdb} {self.nhmsb}" - if self.ladas_cpl != 'None' : - self.ladas_coupling = int(self.ladas_cpl) if self.rstloc != 'None' : rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' assert os.path.isdir(rstloc_) # make sure rstloc_ is a valid directory @@ -175,25 +171,25 @@ class LDASsetup: ### check if ldas is coupled to adas; if so, set/overwrite input parameters accordingly self.adas_expdir = '' - if self.ladas_coupling > 0 : + if self.ladas_cpl > 0 : self.adas_expdir = os.path.dirname( self.exphome) self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir self.adas_expid = os.path.basename(self.adas_expdir) self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' - if self.ladas_coupling == 1 : + if self.ladas_cpl == 1 : # ldas coupled with determistic component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' - self.nens = 24 #for now hardwire nens for atm det - elif self.ladas_coupling == 2 : + self.nens = 24 # for now, hardwire nens for atm det + elif self.ladas_cpl == 2 : # ldas coupled with ensemble component of adas self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' self.nens = 32 # for now, hardwire nens for atm ens else : - exit("Error. Unknown value of ladas_coupling.\n") + exit("Error. Unknown value of self.ladas_cpl.\n") self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens self.first_ens_id = 1 self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id @@ -208,23 +204,26 @@ class LDASsetup: self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' - # the following are not in default rqdExeInp list + # the following are not in default rqdExeInp list; hardwire for now self.rqdExeInp['LAND_ASSIM'] = "YES" self.rqdExeInp['MET_HINTERP'] = 0 self.rqdExeInp['LANDASSIM_DT'] = "10800" self.rqdExeInp['LANDASSIM_T0'] = "013000" - self.rqdExeInp['JOB_SGMT'] = "00000000 060000" + self.rqdExeInp['JOB_SGMT'] = "00000000 060000" # same as length of one ADAS cycle self.rqdExeInp['NUM_SGMT'] = 1 self.rqdExeInp['FORCE_DTSTEP'] = 3600 - dt_str = f"{self.nymdb} {self.nhmsb}" - dt = datetime.strptime(dt_str, "%Y%m%d %H%M%S") - dt_new = dt + timedelta(hours=6) - dt_str_new = dt_new.strftime("%Y%m%d %H%M%S") - self.rqdExeInp['END_DATE'] = dt_str_new + # determine END_DATE = BEG_DATE + TIME_STEP_OF_ADAS_CYCLE + _beg_date = datetime.strptime( self.rqdExeInp['BEG_DATE'], "%Y%m%d %H%M%S") + _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) + _end_date = _beg_date + timedelta(hours=6) + + self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") + self.rqdExeInp['NML_INPUT_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/SPECnml/" self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" - #### + + # end if self.ladas_cpl > 0 for key in rqdExeInpKeys : assert key in self.rqdExeInp,' "%s" is required in the input file %s' % (key,self.exeinpfile) @@ -299,11 +298,11 @@ class LDASsetup: if 'NUM_SGMT' not in self.rqdExeInp: self.rqdExeInp['NUM_SGMT'] = 1 - _years = int(self.rqdExeInp['JOB_SGMT'][0:4]) - _months = int(self.rqdExeInp['JOB_SGMT'][4:6]) - _days = int(self.rqdExeInp['JOB_SGMT'][6:8]) + _years = int(self.rqdExeInp['JOB_SGMT'][ 0: 4]) + _months = int(self.rqdExeInp['JOB_SGMT'][ 4: 6]) + _days = int(self.rqdExeInp['JOB_SGMT'][ 6: 8]) assert self.rqdExeInp['JOB_SGMT'][8] == ' ' and self.rqdExeInp['JOB_SGMT'][9] != ' ', "JOB_SGMT format is not right" - _hours = int(self.rqdExeInp['JOB_SGMT'][9:11]) + _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) _mins = int(self.rqdExeInp['JOB_SGMT'][11:13]) _seconds= int(self.rqdExeInp['JOB_SGMT'][13:15]) @@ -526,12 +525,12 @@ class LDASsetup: inpDictFromFile = self._parseInputFile(cmdLineArgs['batinpfile']) - if self.ladas_coupling > 0 : + if self.ladas_cpl > 0 : if cmdLineArgs['account'] != 'None': self.rqdRmInp['account'] = cmdLineArgs['account'] - self.rqdRmInp['walltime'] = "00:30:00" - self.rqdRmInp['ntasks_model'] = 120 - self.rqdRmInp['ntasks-per-node'] = 60 + self.rqdRmInp['walltime'] = "00:30:00" + self.rqdRmInp['ntasks_model'] = 120 + self.rqdRmInp['ntasks-per-node'] = 46 # 46 works on Cascade Lake and Milan else : # REQUIRED inputs for key in rqdRmInpKeys: @@ -610,6 +609,9 @@ class LDASsetup: else: self.optRmInp['writers-per-node'] = 0 + + # end __init__ + # ----------------------------------------------------------------------------------- def _parseInputFile(self, inpfile): @@ -642,7 +644,7 @@ class LDASsetup: if position>0: # strip out comment line = line[:position] # we expect a line to be of the form - # key = value + # key : value assert ':' in line, errstr % (linenum, inpfile) key, val = line.split(':',1) @@ -1132,7 +1134,7 @@ class LDASsetup: special_nml=[] if 'NML_INPUT_PATH' in self.rqdExeInp : special_nml = glob.glob(self.rqdExeInp['NML_INPUT_PATH']+'/LDASsa_SPECIAL_inputs_*.nml') - if self.ladas_coupling > 0: + if self.ladas_cpl > 0: special_nml = glob.glob(self.rqdExeInp['NML_INPUT_PATH']+'/'+ self.rqdExeInp['EXP_DOMAIN'] + '/LDASsa_SPECIAL_inputs_*.nml') for nmlfile in special_nml: @@ -1192,7 +1194,7 @@ class LDASsetup: print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) # take HISTdet or HISTens if ladas - if shortfile =='HISTdet.rc' and self.ladas_coupling == 1 : + if shortfile =='HISTdet.rc' and self.ladas_cpl == 1 : tmprcfile=self.rundir+'/HISTORY.rc' histrc_file=rcfile shutil.copy2(rcfile, tmprcfile) @@ -1200,7 +1202,7 @@ class LDASsetup: print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GRIDNAME',self.rqdExeInp['GRIDNAME'])) - if shortfile =='HISTens.rc' and self.ladas_coupling == 2 : + if shortfile =='HISTens.rc' and self.ladas_cpl == 2 : tmprcfile=self.rundir+'/HISTORY.rc' histrc_file=rcfile shutil.copy2(rcfile, tmprcfile) @@ -1224,7 +1226,7 @@ class LDASsetup: for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('NUM_SGMT:','NUM_SGMT: %d'% _num_sgmt)) for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace('BEG_DATE:',self.begDates[0].strftime('BEG_DATE: %Y%m%d %H%M%S'))) + print (line.rstrip().replace('BEG_DATE:',self.begDates[ 0].strftime('BEG_DATE: %Y%m%d %H%M%S'))) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('END_DATE:',self.endDates[-1].strftime('END_DATE: %Y%m%d %H%M%S'))) @@ -1486,7 +1488,7 @@ class LDASsetup: MY_MODEL = self.catch, MY_POSTPROC_HIST = str(self.rqdExeInp['POSTPROC_HIST']), MY_FIRST_ENS_ID = str(self.first_ens_id), - MY_LADAS_COUPLING = str(self.ladas_coupling), + MY_LADAS_COUPLING = str(self.ladas_cpl), MY_ENSEMBLE_FORCING= self.rqdExeInp.get('ENSEMBLE_FORCING', 'NO').upper(), MY_ADAS_EXPDIR = self.adas_expdir, MY_EXPDIR = self.expdir, @@ -1518,126 +1520,148 @@ def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): """ Private method: print sample exe input """ - - print ('####################################################################################') - print ('# #') - print ('# REQUIRED INPUTS #') - print ('# #') - print ('# These inputs are needed to set up output dir structure. #') - print ('# #') - print ('####################################################################################') - print () - - print ('############################################################') - print ('# #') - print ('# EXPERIMENT INFO #') - print ('# #') - print ('# Format for start/end times is yyyymmdd hhmmss. #') - print ('# #') - print ('############################################################') - print () - print ('EXP_ID:') - print ('EXP_DOMAIN:') - print ('NUM_LDAS_ENSEMBLE:') - print ('BEG_DATE:') - print ('END_DATE:') - print () - print ('############################################################') - print ('# #') - print ('# RESTART INFO #') - print ('# #') - print ('# (i) Select "RESTART" option: #') - print ('# #') - print ('# Use one of the following options if you *have* a #') - print ('# GEOSldas restart file: #') - print ('# #') - print ('# RESTART: 1 #') - print ('# YES, have restart file from GEOSldas #') - print ('# in SAME tile space (grid) with SAME boundary #') - print ('# conditions and SAME snow model parameter (WEMIN). #') - print ('# The restart domain can be for the same or #') - print ('# a larger one. #') - print ('# #') - print ('# RESTART: 2 #') - print ('# YES, have restart file from GEOSldas but #') - print ('# in a DIFFERENT tile space (grid) or with #') - print ('# DIFFERENT boundary conditions or DIFFERENT snow #') - print ('# model parameter (WEMIN). #') - print ('# Restart *must* be for the GLOBAL domain. #') - print ('# #') - print ('# Use one of the following options if you DO NOT have a #') - print ('# GEOSldas restart file #') - print ('# (works for global domain ONLY!): #') - print ('# #') - print ('# RESTART: 0 #') - print ('# Cold start from some old restart for Jan 1, 0z. #') - print ('# #') - print ('# RESTART: M #') - print ('# Re-tile from archived MERRA-2 restart file. #') - print ('# #') - print ('# -------------------------------------------------------- #') - print ('# IMPORTANT: #') - print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') - print ('# all cases. #') - print ('# -------------------------------------------------------- #') - print ('# #') - print ('# #') - print ('# (ii) Specify experiment ID/location of restart file: #') - print ('# #') - print ('# For RESTART=1 or RESTART=2: #') - print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') - print ('# restarts stored as follows: #') - print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') - print ('# #') - print ('# For RESTART=0 or RESTART=M: #') - print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') - print ('# and RESTART_DOMAIN. #') - print ('# #') - print ('############################################################') - print () - print ('RESTART:') - print ('#RESTART_ID:') - print ('#RESTART_PATH:') - print ('#RESTART_DOMAIN:') - print () - print ('############################################################') - print ('# #') - print ('# SURFACE METEOROLOGICAL FORCING #') - print ('# #') - print ('# Surface meteorological forcing time step is in seconds. #') - print ('# #') - print ('# NOTE: #') - print ('# When forcing is on cube-sphere (CS) grid, must use: #') - print ('# - Model tile space (BCS) derived from same CS grid. #') - print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') - print ('# #') - print ('# For more information, see: #') - print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# #') - print ('############################################################') - print () - print ('MET_TAG:') - print ('MET_PATH:') - print ('FORCE_DTSTEP:') - print () - print ('############################################################') - print ('# #') - print ('# LAND BOUNDARY CONDITIONS (BCS) #') - print ('# #') - print ('# Path to and (atmospheric) resolution of BCS. #') - print ('# Path includes BCS_VERSION (unless LADAS_COUPLING>0). #') - print ('# #') - print ('# For more information, see: #') - print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# [..]/GEOSsurface_GridComp/Utils/Raster/make_bcs #') - print ('# #') - print ('############################################################') - print () - print ('BCS_PATH:') - print ('BCS_RESOLUTION:') - print () - print ('############################################################') + if ladas_cpl == 0 : + + # stand-alone (offline) LDAS: + # sample exeinp file includes placeholders for inputs that the user needs to provide + + print ('####################################################################################') + print ('# #') + print ('# REQUIRED INPUTS #') + print ('# #') + print ('# These inputs are needed to set up output dir structure. #') + print ('# #') + print ('####################################################################################') + print () + print ('############################################################') + print ('# #') + print ('# EXPERIMENT INFO #') + print ('# #') + print ('# Format for start/end times is yyyymmdd hhmmss. #') + print ('# #') + print ('############################################################') + print () + print ('EXP_ID:') + print ('EXP_DOMAIN:') + print ('NUM_LDAS_ENSEMBLE:') + print ('BEG_DATE:') + print ('END_DATE:') + print () + print ('############################################################') + print ('# #') + print ('# RESTART INFO #') + print ('# #') + print ('# (i) Select "RESTART" option: #') + print ('# #') + print ('# Use one of the following options if you *have* a #') + print ('# GEOSldas restart file: #') + print ('# #') + print ('# RESTART: 1 #') + print ('# YES, have restart file from GEOSldas #') + print ('# in SAME tile space (grid) with SAME boundary #') + print ('# conditions and SAME snow model parameter (WEMIN). #') + print ('# The restart domain can be for the same or #') + print ('# a larger one. #') + print ('# #') + print ('# RESTART: 2 #') + print ('# YES, have restart file from GEOSldas but #') + print ('# in a DIFFERENT tile space (grid) or with #') + print ('# DIFFERENT boundary conditions or DIFFERENT snow #') + print ('# model parameter (WEMIN). #') + print ('# Restart *must* be for the GLOBAL domain. #') + print ('# #') + print ('# Use one of the following options if you DO NOT have a #') + print ('# GEOSldas restart file #') + print ('# (works for global domain ONLY!): #') + print ('# #') + print ('# RESTART: 0 #') + print ('# Cold start from some old restart for Jan 1, 0z. #') + print ('# #') + print ('# RESTART: M #') + print ('# Re-tile from archived MERRA-2 restart file. #') + print ('# #') + print ('# -------------------------------------------------------- #') + print ('# IMPORTANT: #') + print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') + print ('# all cases. #') + print ('# -------------------------------------------------------- #') + print ('# #') + print ('# #') + print ('# (ii) Specify experiment ID/location of restart file: #') + print ('# #') + print ('# For RESTART=1 or RESTART=2: #') + print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') + print ('# restarts stored as follows: #') + print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') + print ('# #') + print ('# For RESTART=0 or RESTART=M: #') + print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') + print ('# and RESTART_DOMAIN. #') + print ('# #') + print ('############################################################') + print () + print ('RESTART:') + print ('#RESTART_ID:') + print ('#RESTART_PATH:') + print ('#RESTART_DOMAIN:') + print () + print ('############################################################') + print ('# #') + print ('# SURFACE METEOROLOGICAL FORCING #') + print ('# #') + print ('# Surface meteorological forcing time step is in seconds. #') + print ('# #') + print ('# NOTE: #') + print ('# When forcing is on cube-sphere (CS) grid, must use: #') + print ('# - Model tile space (BCS) derived from same CS grid. #') + print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') + print ('# #') + print ('# For more information, see: #') + print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') + print ('# #') + print ('############################################################') + print () + print ('MET_TAG:') + print ('MET_PATH:') + print ('FORCE_DTSTEP:') + print () + print ('############################################################') + print ('# #') + print ('# LAND BOUNDARY CONDITIONS (BCS) #') + print ('# #') + print ('# Path to and (atmospheric) resolution of BCS. #') + print ('# Path includes BCS_VERSION. #') + print ('# #') + print ('# For more information, see: #') + print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') + print ('# [..]/GEOSsurface_GridComp/Utils/Raster/make_bcs #') + print ('# #') + print ('############################################################') + print () + print ('BCS_PATH:') + print ('BCS_RESOLUTION:') + print () + print ('############################################################') + + else : + + # LDAS coupled to ADAS: + # exclude "required" inputs from sample exeinp file because they will be + # provided by the ADAS setup script (fvsetup) + + print ('####################################################################################') + print ('# #') + print ('# THIS SAMPLE EXEINP FILE HAS BEEN CUSTOMIZED FOR THE COUPLED LAND-ATM DAS #') + print ('# #') + print ('# The ADAS setup script (fvsetup) provides EXP_ID, BEG_DATE, END_DATE, etc #') + print ('# #') + print ('####################################################################################') + + # end if ladas_cpl==0 + + # add defaults from GEOSldas_LDAS.rc + _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory with open(_fn) as _f: @@ -1650,40 +1674,31 @@ def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): print () print () + # add land model parameter defaults from GEOS_SurfaceGridComp.rc + _fn = '../etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory + if ladas_cpl == 0 : + use_rc_defaults = 'GEOSldas=>' # use defaults for LDAS + else : + use_rc_defaults = 'GEOSagcm=>' # use defaults for AGCM + with open(_fn) as _f : - i_ = 1 - for line in _f: - if ( 5<=i_ and i_<=21) : # ignore lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited - i_ +=1 - continue - if ladas_cpl > 0 : - if 'GEOSldas=>' in line: # ignore lines with defaults for GEOSldas + i_ = 1 + for line in _f: + if ( 5<=i_ and i_<=21) : # ignore lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited i_ +=1 continue - if '"GEOSagcm=>"' in line: - sys.stdout.write(line) - elif 'GEOSagcm=>' in line: - line0 = line.split("GEOSagcm=>")[1] - sys.stdout.write(line0) - elif not line.strip() or line.strip().startswith('#'): - sys.stdout.write(line) - sys.stdout.flush() - i_ += 1 - else : - if 'GEOSagcm=>' in line: # ignore lines with defaults for GEOSagcm - i_ +=1 - continue - if '"GEOSldas=>"' in line: - sys.stdout.write(line) - elif 'GEOSldas=>' in line: - line0 = line.split("GEOSldas=>")[1] - sys.stdout.write(line0) - elif not line.strip() or line.strip().startswith('#'): - sys.stdout.write(line) - sys.stdout.flush() - i_ += 1 + if '"GEOSagcm=>"' in line: # ignore odd occurrence of "GEOSgacm=>" in header lines + sys.stdout.write(line) + elif use_rc_defaults in line: # process lines that contain string "use_rc_defaults" + line0 = line.split(use_rc_defaults)[1] + sys.stdout.write(line0) + elif not line.strip() or line.strip().startswith('#'): + sys.stdout.write(line) + sys.stdout.flush() + i_ += 1 + print () print () @@ -1733,19 +1748,19 @@ def parseCmdLine(): p = argparse.ArgumentParser( description= \ "Script to setup a GEOSldas experiment. The script requires "\ - "two (2) input files, one for the Fortran executable and the " \ - "other for the resource manager (SLURM). For sample input " \ + "two (2) input files, one for the experiment inputs and the " \ + "other for the resource manager (SLURM). To create sample input " \ "files use './ldas_setup sample -h'.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) p_sub = p.add_subparsers(help='sub-command help') - # subparser: sample command + # subparser: "sample" command p_sample = p_sub.add_parser( 'sample', help='write sample input files', description='Print sample input files - either for the '\ - 'Fortran executable or the resource manager (SLURM)', + 'experiment inputs or the resource manager (SLURM)', ) group = p_sample.add_mutually_exclusive_group(required=True) group.add_argument( @@ -1758,17 +1773,20 @@ def parseCmdLine(): help='print sample input file for the resource manager (SLURM)', action='store_true', ) + + ladas_cpl_help='land-atm DAS coupling mode: default=0 (not coupled); LDAS coupled with (1) ADAS deterministic member or (2) ADAS ensemble', + p_sample.add_argument( '--ladas_cpl', - help='land-atm DAS coupling mode: LDAS coupled with ADAS' , + help=ladas_cpl_help, type=str, default='None' ) - # subparser: setup command + # subparser: "setup" command p_setup = p_sub.add_parser( 'setup', help='setup LDAS experiment', - description="The 'setup' sub-command is used to setup a GEOSldas " \ + description="The 'setup' sub-command is used to set up a GEOSldas " \ "experiment. The positional argument 'exphome' is used to create " \ "work_path (=exphome+/output) and run_path (=exphome+/run)." ) @@ -1790,6 +1808,11 @@ def parseCmdLine(): # the following command line arguments, if present, take precedence over what # is specified in the exeinp and batinp files + p_setup.add_argument( + '--ladas_cpl', + help=ladas_cpl_help, + type=str, default='None' + ) p_setup.add_argument( '--account', help='overwrites computing/sponsor account from batinp file', @@ -1805,11 +1828,6 @@ def parseCmdLine(): help='overwrites time in BEG_DATE from exeinp file', type=str, default='None' ) - p_setup.add_argument( - '--ladas_cpl', - help='land-atm DAS coupling mode: LDAS coupled with (1) ADAS deterministic member or (2) ADAS ensemble', - type=str, default='None' - ) p_setup.add_argument( '--agcm_res', help='AGCM resolution associated with boundary conditions', From ef43e7e94d539df3b41e8db113673eda3ecd3195 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 15 May 2025 13:12:56 -0400 Subject: [PATCH 16/36] additional commandline inputs for ladas --- GEOSldas_App/ldas_setup | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 35f9e8cb..41325acb 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -102,6 +102,9 @@ class LDASsetup: self.agcm_res = cmdLineArgs['agcm_res'] self.bcs_version = cmdLineArgs['bcs_version'] self.rstloc = cmdLineArgs['rstloc'] + self.adas_cyc = cmdLineArgs['adas_cyc'] + self.specnml_path = cmdLineArgs['specnml_path'] + self.mwrtm_path = cmdLineArgs['mwrtm_path'] # obsolete command line args self.runmodel = cmdLineArgs['runmodel'] @@ -168,7 +171,7 @@ class LDASsetup: self.rstloc = os.path.abspath(rstloc_) self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) - + ### check if ldas is coupled to adas; if so, set/overwrite input parameters accordingly self.adas_expdir = '' if self.ladas_cpl > 0 : @@ -209,7 +212,10 @@ class LDASsetup: self.rqdExeInp['MET_HINTERP'] = 0 self.rqdExeInp['LANDASSIM_DT'] = "10800" self.rqdExeInp['LANDASSIM_T0'] = "013000" - self.rqdExeInp['JOB_SGMT'] = "00000000 060000" # same as length of one ADAS cycle + self.rqdExeInp['JOB_SGMT'] = "00000000 060000" #default + # same as length of one ADAS cycle + if self.adas_cyc != 'None' : + self.rqdExeInp['JOB_SGMT'] = '00000000 '+ self.adas_cyc self.rqdExeInp['NUM_SGMT'] = 1 self.rqdExeInp['FORCE_DTSTEP'] = 3600 @@ -219,9 +225,13 @@ class LDASsetup: _end_date = _beg_date + timedelta(hours=6) self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") - + #default or input from command line self.rqdExeInp['NML_INPUT_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/SPECnml/" - self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" + if self.specnml_path != 'None' : + self.rqdExeInp['NML_INPUT_PATH'] = self.specnml_path + self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" + if self.mwrtm_path != 'None' : + self.rqdExeInp['MWRTM_PATH'] = self.mwrtm_path # end if self.ladas_cpl > 0 @@ -1843,6 +1853,22 @@ def parseCmdLine(): help='location of LDAS restarts (restart_path/restart_id)', type=str, default='None' ) + p_setup.add_argument( + '--adas_cyc', + help='ADAS analysis window ', + type=str, default='None' + ) + p_setup.add_argument( + '--specnml_path', + help='path to ldas spec nml ', + type=str, default='None' + ) + p_setup.add_argument( + '--mwrtm_path', + help='path to ldas mwrtm parameters ', + type=str, default='None' + ) + # obsolete command line args p_setup.add_argument( From 7a023c93e9994b4c296cf8fb24f93ad2941a65e0 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 15 May 2025 22:34:15 -0400 Subject: [PATCH 17/36] minor edit insert adas_cyc input in JOB_SGMT --- GEOSldas_App/ldas_setup | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 41325acb..77bcf056 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -212,10 +212,11 @@ class LDASsetup: self.rqdExeInp['MET_HINTERP'] = 0 self.rqdExeInp['LANDASSIM_DT'] = "10800" self.rqdExeInp['LANDASSIM_T0'] = "013000" - self.rqdExeInp['JOB_SGMT'] = "00000000 060000" #default - # same as length of one ADAS cycle - if self.adas_cyc != 'None' : - self.rqdExeInp['JOB_SGMT'] = '00000000 '+ self.adas_cyc + jsgmt1 = "00000000" + jsgmt2 = "060000" + if self.adas_cyc != 'None' : #ADAS cycle + jsgmt2 = self.adas_cyc + self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" self.rqdExeInp['NUM_SGMT'] = 1 self.rqdExeInp['FORCE_DTSTEP'] = 3600 From 86056e5676f240fe2d22cb31dbe0e59fc10bfd4d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 19 May 2025 13:03:16 -0400 Subject: [PATCH 18/36] fixed errors in most recent merge (conflict resolution); white-space changes (ldas_setup) --- GEOSldas_App/ldas_setup | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 58cd7eb5..e0b5274f 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -126,7 +126,7 @@ class LDASsetup: self.out_path = None self.inpdir = None self.exefyl = None - self.islocal = False + self.isZoomIn = False self.catch = '' self.has_mwrtm = False self.has_vegopacity = False @@ -357,7 +357,7 @@ class LDASsetup: # make sure catchment and vegdyn restart files ( at least one for each) exist if 'CATCH_DEF_FILE' not in self.rqdExeInp : - self.rqdExeInp['CATCH_DEF_FILE']= self.bcs_land + 'clsm/catchment.def' + self.rqdExeInp['CATCH_DEF_FILE']= self.bcs_dir_land + 'clsm/catchment.def' if (self.with_land) : assert os.path.isfile(self.rqdExeInp['CATCH_DEF_FILE']),"[%s] file does not exist " % self.rqdExeInp['CATCH_DEF_FILE'] @@ -379,30 +379,30 @@ class LDASsetup: self.rqdExeInp['LNFM_FILE'] = '' tile_file_format = self.rqdExeInp.get('TILE_FILE_FORMAT', 'DEFAULT') if int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1 : - txt_tile = glob.glob(self.bcs_geom + '*.til') - nc4_tile = glob.glob(self.bcs_geom + '*.nc4') - if tile_file_format.upper() == 'TXT' : self.rqdExeInp['TILING_FILE'] = txt_tile[0] + txt_tile = glob.glob(self.bcs_dir_geom + '*.til') + nc4_tile = glob.glob(self.bcs_dir_geom + '*.nc4') + if tile_file_format.upper() == 'TXT' : self.rqdExeInp['TILING_FILE'] = txt_tile[0] if tile_file_format.upper() == 'DEFAULT' : self.rqdExeInp['TILING_FILE'] = (txt_tile+nc4_tile)[-1] - self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] - tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') + self.rqdExeInp['GRN_FILE'] = glob.glob(self.bcs_dir_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE'] = glob.glob(self.bcs_dir_land + 'lai_clim_*.data' )[0] + tmp_ = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data') if (len(tmp_) ==1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_dir_land + 'ndvi_clim_*.data' )[0] + self.rqdExeInp['NIRDF_FILE'] = glob.glob(self.bcs_dir_land + 'nirdf_*.dat' )[0] + self.rqdExeInp['VISDF_FILE'] = glob.glob(self.bcs_dir_land + 'visdf_*.dat' )[0] else : inpdir=self.rqdExeInp['RESTART_PATH']+self.rqdExeInp['RESTART_ID']+'/input/' - self.rqdExeInp['TILING_FILE'] =os.path.realpath(glob.glob(inpdir+'*tile.data')[0]) - self.rqdExeInp['GRN_FILE']= os.path.realpath(glob.glob(inpdir+'green*data')[0]) - self.rqdExeInp['LAI_FILE']= os.path.realpath(glob.glob(inpdir+'lai*data')[0]) - tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE'] = os.path.realpath(glob.glob(inpdir+'*tile.data')[0]) + self.rqdExeInp['GRN_FILE'] = os.path.realpath(glob.glob(inpdir+'green*data')[0]) + self.rqdExeInp['LAI_FILE'] = os.path.realpath(glob.glob(inpdir+'lai*data' )[0]) + tmp_ = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['NDVI_FILE']= os.path.realpath(glob.glob(inpdir+'ndvi*data')[0]) - self.rqdExeInp['NIRDF_FILE']= os.path.realpath(glob.glob(inpdir+'nirdf*data')[0]) - self.rqdExeInp['VISDF_FILE']= os.path.realpath(glob.glob(inpdir+'visdf*data')[0]) + self.rqdExeInp['NDVI_FILE'] = os.path.realpath(glob.glob(inpdir+'ndvi*data' )[0]) + self.rqdExeInp['NIRDF_FILE'] = os.path.realpath(glob.glob(inpdir+'nirdf*data')[0]) + self.rqdExeInp['VISDF_FILE'] = os.path.realpath(glob.glob(inpdir+'visdf*data')[0]) if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) == 2 : @@ -423,20 +423,20 @@ class LDASsetup: self.in_tilefile =os.path.realpath(in_tilefiles_[0]) if os.path.isfile(ldas_domain): - txt_tile = glob.glob(self.bcs_geom + '*.til') - nc4_tile = glob.glob(self.bcs_geom + '*.nc4') + txt_tile = glob.glob(self.bcs_dir_geom + '*.til') + nc4_tile = glob.glob(self.bcs_dir_geom + '*.nc4') if tile_file_format.upper() == 'TXT' : self.rqdExeInp['TILING_FILE'] = txt_tile[0] if tile_file_format.upper() == 'DEFAULT' : self.rqdExeInp['TILING_FILE'] = (txt_tile+nc4_tile)[-1] - self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] - tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') + self.rqdExeInp['GRN_FILE'] = glob.glob(self.bcs_dir_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE'] = glob.glob(self.bcs_dir_land + 'lai_clim_*.data' )[0] + tmp_ = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data')[0] - self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_dir_land + 'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE'] = glob.glob(self.bcs_dir_land + 'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE'] = glob.glob(self.bcs_dir_land + 'visdf_*.dat')[0] + self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_dir_land + 'lnfm_clim_*.data' )[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_dir_land + 'ndvi_clim_*.data' )[0] + self.rqdExeInp['NIRDF_FILE'] = glob.glob(self.bcs_dir_land + 'nirdf_*.dat' )[0] + self.rqdExeInp['VISDF_FILE'] = glob.glob(self.bcs_dir_land + 'visdf_*.dat' )[0] if 'GRIDNAME' not in self.rqdExeInp : tmptile = os.path.realpath(self.rqdExeInp['TILING_FILE']) @@ -920,7 +920,7 @@ class LDASsetup: os.symlink(bc,myBC) if ("catchcn" in self.catch): - os.symlink(self.bcs_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ + os.symlink(self.bcs_dir_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') # create and link restart From 14f5186b61c0d8635fba1566955baf72854399f6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Mon, 19 May 2025 16:34:59 -0400 Subject: [PATCH 19/36] remove README.exeinp.txt.forladas (no longer needed) --- .../LADAS/README.exeinp.txt.forladas | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas diff --git a/GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas b/GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas deleted file mode 100644 index 4ba42f99..00000000 --- a/GEOSldas_App/sample_config_files/LADAS/README.exeinp.txt.forladas +++ /dev/null @@ -1,39 +0,0 @@ -# -# README on GEOSldas "exeinp" file for LADAS -# -# for the GEOSldas instance that is coupled with -# Hy4dEnVar ADAS: -# -# (1) Create exeinp template using: -# ldas_setup sample --exeinp > ldas_exeinp.txt -# -# (2) Use the resource parameter settings below when editing ldas_exeinp.txt -# -# (3) The following resource parameters are provided via fvsetup, -# which supersede the default in ldas_exeinp.txt -# EXP_ID -# EXP_DOMAIN -# BEG_DATE -# RESTART_ID -# RESTART_PATH -# RESTART_DOMAIN -# MET_TAG -# MET_PATH -# bcs_version in BCS_PATH -# BCS_RESOLUTION -# LADAS_COUPLING -# ADAS_EXPDIR -# GID -# -# (4) The following resource parameters are hard-wired for ladas -# which supersede the default in ldas_exeinp.txt -# MET_HINTERP -# LANDASSIM_DT -# LANDASSIM_T0 -# FIRST_ENS_ID -# ENSEMBLE_FORCING -# JOB_SGMT -# NUM_SGMT -# NUM_LDAS_ENSEMBLE is hard-wired as 32 if coupled with atmens -############################################################################## - From ae2717e9bddc2ea11ba9fcc96da929b8abfdb23a Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 20 May 2025 11:27:36 -0400 Subject: [PATCH 20/36] edits of previous commit (ldas_setup): - do not repeat identical lines when processing HISTORY file for coupled land-atm DAS - for length of ADAS analysis window, use variable name and units as in fvsetup - removed hardwired length of ADAS analysis window to determine END_DATE - for coupled land-atm DAS, ensure all command line args are supplied - renamed command line arg for LDAS nml input files --- GEOSldas_App/ldas_setup | 167 ++++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 75 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index e0b5274f..847318af 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -98,14 +98,14 @@ class LDASsetup: self.exphome = os.path.abspath(exphome_) self.verbose = cmdLineArgs['verbose'] - # command line args for coupled land-atm DAS + # command line args for coupled land-atm DAS (see "help" strings in parseCmdLine() for details) self.nymdb = cmdLineArgs['nymdb'] self.nhmsb = cmdLineArgs['nhmsb'] self.agcm_res = cmdLineArgs['agcm_res'] self.bcs_version = cmdLineArgs['bcs_version'] self.rstloc = cmdLineArgs['rstloc'] - self.adas_cyc = cmdLineArgs['adas_cyc'] - self.specnml_path = cmdLineArgs['specnml_path'] + self.varwindow = cmdLineArgs['varwindow'] + self.LDAS_nml_path = cmdLineArgs['LDAS_nml_path'] self.mwrtm_path = cmdLineArgs['mwrtm_path'] # obsolete command line args @@ -181,64 +181,73 @@ class LDASsetup: ### check if ldas is coupled to adas; if so, set/overwrite input parameters accordingly self.adas_expdir = '' if self.ladas_cpl > 0 : - self.adas_expdir = os.path.dirname( self.exphome) - self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir - self.adas_expid = os.path.basename(self.adas_expdir) - self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' - if self.ladas_cpl == 1 : - # ldas coupled with determistic component of adas - self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' - self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' - self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' - self.nens = 24 # for now, hardwire nens for atm det - elif self.ladas_cpl == 2 : - # ldas coupled with ensemble component of adas - self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' - self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' - self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' - self.nens = 32 # for now, hardwire nens for atm ens - else : - exit("Error. Unknown value of self.ladas_cpl.\n") - self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens - self.first_ens_id = 1 - self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id - self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' - - # when coupled to ADAS, "BCS_PATH" EXCLUDE bcs version info - # hard-wired BCS_PATH for now - self.rqdExeInp['BCS_PATH'] = "/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles" - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'].rstrip('/') + '/' + self.bcs_version - if self.bcs_version == "Icarus-NLv3" : - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' - self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' - self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + + # make sure all necessary command line arguments were supplied + if self.nymdb == 'None' : exit("Error. Must have command line arg nymdb for coupled land-atm DAS.\n") + if self.nhmsb == 'None' : exit("Error. Must have command line arg nhmsb for coupled land-atm DAS.\n") + if self.agcm_res == 'None' : exit("Error. Must have command line arg agcm_res for coupled land-atm DAS.\n") + if self.bcs_version == 'None' : exit("Error. Must have command line arg bcs_version for coupled land-atm DAS.\n") + if self.rstloc == 'None' : exit("Error. Must have command line arg rstloc for coupled land-atm DAS.\n") + if self.varwindow == 'None' : exit("Error. Must have command line arg varwindow for coupled land-atm DAS.\n") + if self.LDAS_nml_path == 'None' : exit("Error. Must have command line arg LDAS_nml_path for coupled land-atm DAS.\n") + if self.mwrtm_path == 'None' : exit("Error. Must have command line arg mwrtm_path for coupled land-atm DAS.\n") + + self.adas_expdir = os.path.dirname( self.exphome) + self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir + self.adas_expid = os.path.basename(self.adas_expdir) + self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' + if self.ladas_cpl == 1 : + # ldas coupled with determistic component of adas + self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' + self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' + self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' + self.nens = 24 # for now, hardwire nens for atm det + elif self.ladas_cpl == 2 : + # ldas coupled with ensemble component of adas + self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' + self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' + self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' + self.nens = 32 # for now, hardwire nens for atm ens + else : + exit("Error. Unknown value of self.ladas_cpl.\n") + self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens + self.first_ens_id = 1 + self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id + self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + + # when coupled to ADAS, "BCS_PATH" EXCLUDE bcs version info + # hard-wired BCS_PATH for now + self.rqdExeInp['BCS_PATH'] = "/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles" + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'].rstrip('/') + '/' + self.bcs_version + if self.bcs_version == "Icarus-NLv3" : + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' + self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' + self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' - # the following are not in default rqdExeInp list; hardwire for now - self.rqdExeInp['LAND_ASSIM'] = "YES" - self.rqdExeInp['MET_HINTERP'] = 0 - self.rqdExeInp['LANDASSIM_DT'] = "10800" - self.rqdExeInp['LANDASSIM_T0'] = "013000" - jsgmt1 = "00000000" - jsgmt2 = "060000" - if self.adas_cyc != 'None' : #ADAS cycle - jsgmt2 = self.adas_cyc - self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" - self.rqdExeInp['NUM_SGMT'] = 1 - self.rqdExeInp['FORCE_DTSTEP'] = 3600 - - # determine END_DATE = BEG_DATE + TIME_STEP_OF_ADAS_CYCLE - _beg_date = datetime.strptime( self.rqdExeInp['BEG_DATE'], "%Y%m%d %H%M%S") - _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) - _end_date = _beg_date + timedelta(hours=6) - - self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") - #default or input from command line - self.rqdExeInp['NML_INPUT_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/SPECnml/" - if self.specnml_path != 'None' : - self.rqdExeInp['NML_INPUT_PATH'] = self.specnml_path - self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" - if self.mwrtm_path != 'None' : - self.rqdExeInp['MWRTM_PATH'] = self.mwrtm_path + # the following are not in default rqdExeInp list; hardwire for now + self.rqdExeInp['LAND_ASSIM'] = "YES" + self.rqdExeInp['MET_HINTERP'] = 0 + self.rqdExeInp['LANDASSIM_DT'] = "10800" + self.rqdExeInp['LANDASSIM_T0'] = "013000" + jsgmt1 = "00000000" + jsgmt2 = hours_to_hhmmss(self.varwindow/60) # convert minutes to HHMMSS + self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" + self.rqdExeInp['NUM_SGMT'] = 1 + self.rqdExeInp['FORCE_DTSTEP'] = 3600 + + # determine END_DATE = BEG_DATE + TIME_STEP_OF_ADAS_CYCLE + _beg_date = datetime.strptime( self.rqdExeInp['BEG_DATE'], "%Y%m%d %H%M%S") + _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) + _end_date = _beg_date + timedelta(hours=self.varwindow/60) + + self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") + #default or input from command line + self.rqdExeInp['NML_INPUT_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/SPECnml/" + if self.LDAS_nml_path != 'None' : + self.rqdExeInp['NML_INPUT_PATH'] = self.LDAS_nml_path + self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" + if self.mwrtm_path != 'None' : + self.rqdExeInp['MWRTM_PATH'] = self.mwrtm_path # end if self.ladas_cpl > 0 @@ -1274,16 +1283,8 @@ class LDASsetup: for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) - # take HISTdet or HISTens if ladas - if shortfile =='HISTdet.rc' and self.ladas_cpl == 1 : - tmprcfile=self.rundir+'/HISTORY.rc' - histrc_file=rcfile - shutil.copy2(rcfile, tmprcfile) - for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) - for line in fileinput.input(tmprcfile,inplace=True): - print (line.rstrip().replace('GRIDNAME',self.rqdExeInp['GRIDNAME'])) - if shortfile =='HISTens.rc' and self.ladas_cpl == 2 : + # if coupled land-atm DAS, always use either GEOSldas_HISTdet.rc or GEOSldas_HISTens.rc (depending on ladas_cpl) + if ( shortfile =='HISTdet.rc' and self.ladas_cpl == 1 ) or ( shortfile =='HISTens.rc' and self.ladas_cpl == 2 ): tmprcfile=self.rundir+'/HISTORY.rc' histrc_file=rcfile shutil.copy2(rcfile, tmprcfile) @@ -1939,18 +1940,18 @@ def parseCmdLine(): type=str, default='None' ) p_setup.add_argument( - '--adas_cyc', - help='ADAS analysis window ', + '--varwindow', + help='ADAS analysis window (minutes)', type=str, default='None' ) p_setup.add_argument( - '--specnml_path', - help='path to ldas spec nml ', + '--LDAS_nml_path', + help='path to LDAS (special) nml input files', type=str, default='None' ) p_setup.add_argument( '--mwrtm_path', - help='path to ldas mwrtm parameters ', + help='path to LDAS L-band microwave radiative transfer model (mwrtm) parameters ', type=str, default='None' ) @@ -1978,6 +1979,22 @@ def parseCmdLine(): return p.parse_args() + +def hours_to_hhmmss(hours): + + # Convert hours to timedelta + td = timedelta(hours=hours) + + # Extract hours, minutes, seconds + total_seconds = int(td.total_seconds()) + hours, remainder = divmod(total_seconds, 3600) + minutes, seconds = divmod(remainder, 60) + + # Format as HHMMSS + return f"{hours:02d}{minutes:02d}{seconds:02d}" + + + if __name__=='__main__': resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) From 8dbd52adec16e0f55dce699fa9925b2eae948c78 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Tue, 20 May 2025 12:35:57 -0400 Subject: [PATCH 21/36] edits on varwindow, walltime and nml path default --- GEOSldas_App/ldas_setup | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 847318af..7235af1c 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -230,7 +230,7 @@ class LDASsetup: self.rqdExeInp['LANDASSIM_DT'] = "10800" self.rqdExeInp['LANDASSIM_T0'] = "013000" jsgmt1 = "00000000" - jsgmt2 = hours_to_hhmmss(self.varwindow/60) # convert minutes to HHMMSS + jsgmt2 = hours_to_hhmmss(int(self.varwindow)/60) # convert minutes to HHMMSS self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" self.rqdExeInp['NUM_SGMT'] = 1 self.rqdExeInp['FORCE_DTSTEP'] = 3600 @@ -238,14 +238,11 @@ class LDASsetup: # determine END_DATE = BEG_DATE + TIME_STEP_OF_ADAS_CYCLE _beg_date = datetime.strptime( self.rqdExeInp['BEG_DATE'], "%Y%m%d %H%M%S") _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) - _end_date = _beg_date + timedelta(hours=self.varwindow/60) + _end_date = _beg_date + timedelta(hours=int(self.varwindow)/60) self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") - #default or input from command line - self.rqdExeInp['NML_INPUT_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/SPECnml/" if self.LDAS_nml_path != 'None' : self.rqdExeInp['NML_INPUT_PATH'] = self.LDAS_nml_path - self.rqdExeInp['MWRTM_PATH'] = "/discover/nobackup/qzhang/LDAS_INPUTS/MWRTM/" if self.mwrtm_path != 'None' : self.rqdExeInp['MWRTM_PATH'] = self.mwrtm_path @@ -582,7 +579,7 @@ class LDASsetup: if self.ladas_cpl > 0 : if cmdLineArgs['account'] != 'None': self.rqdRmInp['account'] = cmdLineArgs['account'] - self.rqdRmInp['walltime'] = "00:30:00" + self.rqdRmInp['walltime'] = "01:00:00" self.rqdRmInp['ntasks_model'] = 120 self.rqdRmInp['ntasks-per-node'] = 46 # 46 works on Cascade Lake and Milan else : From d36c72cf6902e79e3d19677d677b7068a38d0aa1 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 20 May 2025 12:55:18 -0400 Subject: [PATCH 22/36] for coupled land-atm DAS, ensure consistency between LANDASSIM_DT and ADAS analyis window (ldas_setup) --- GEOSldas_App/ldas_setup | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 7235af1c..3ff75942 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -227,8 +227,13 @@ class LDASsetup: # the following are not in default rqdExeInp list; hardwire for now self.rqdExeInp['LAND_ASSIM'] = "YES" self.rqdExeInp['MET_HINTERP'] = 0 - self.rqdExeInp['LANDASSIM_DT'] = "10800" - self.rqdExeInp['LANDASSIM_T0'] = "013000" + self.landassim_dt = 10800 # seconds + # make sure ADAS analysis window [minutes] is multiple of LANDASSIM_DT [seconds] + if self.varwindow % self.landassim_dt/60 == 0 : + self.rqdExeInp['LANDASSIM_DT'] = self.landassim_dt + else : + exit("Error. LANDASSIM_DT is inconsistent with ADAS analysis window.\n") + self.rqdExeInp['LANDASSIM_T0'] = "013000" # HHMMSS jsgmt1 = "00000000" jsgmt2 = hours_to_hhmmss(int(self.varwindow)/60) # convert minutes to HHMMSS self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" From 29a2b3cc23e93eb4c183cad831f6b882ede675d6 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 20 May 2025 13:29:52 -0400 Subject: [PATCH 23/36] clean up processing of defaults from GEOS_SurfaceGridComp.rc (ldas_setup) --- GEOSldas_App/ldas_setup | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 3ff75942..b5bad5db 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -680,19 +680,27 @@ class LDASsetup: inpdict = OrderedDict() errstr = "line [%d] of [%s] is not in the form 'key: value'" + # determine which default values to pick from GEOS_SurfaceGridComp.rc + if self.ladas_cpl == 0 : + use_rc_defaults = 'GEOSldas=>' # use defaults for LDAS + else : + use_rc_defaults = 'GEOSagcm=>' # use defaults for AGCM + fin = open(inpfile, 'r') linenum = 0 for line in fin: - linenum += 1 + linenum += 1 line = line.strip() # blank line if not line: - continue - if '"GEOSldas=>"' in line: - continue - # get "GEOSldas=>" default in GEOS_LandGrid.rc - if 'GEOSldas=>' in line: - line = line.split('GEOSldas=>')[1] + continue + if '"GEOSagcm=>"' in line: # echo lines that contain "GEOSagcm=>" (w/ quotation marks) [GEOS_SurfaceGridComp.rc] + continue + if '"GEOSldas=>"' in line: # echo lines that contain "GEOSldas=>" (w/ quotation marks) [GEOS_SurfaceGridComp.rc] + continue + # get 'GEOSldas=>' or 'GEOSagcm=>' defaults in GEOS_SurfaceGridComp.rc + if use_rc_defaults in line: + line = line.split(use_rc_defaults)[1] # handle comments position = line.find('#') if position==0: # comment line @@ -1784,15 +1792,17 @@ def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): with open(_fn) as _f : i_ = 1 for line in _f: - if ( 5<=i_ and i_<=21) : # ignore lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited + if ( 5<=i_ and i_<=21) : # skip over lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited i_ +=1 continue - if '"GEOSagcm=>"' in line: # ignore odd occurrence of "GEOSgacm=>" in header lines + if '"GEOSagcm=>"' in line: # echo lines that contain "GEOSagcm=>" (w/ quotation marks) + sys.stdout.write(line) + elif '"GEOSldas=>"' in line: # echo lines that contain "GEOSldas=>" (w/ quotation marks) sys.stdout.write(line) - elif use_rc_defaults in line: # process lines that contain string "use_rc_defaults" + elif use_rc_defaults in line: # process lines that contain string "use_rc_defaults" line0 = line.split(use_rc_defaults)[1] sys.stdout.write(line0) - elif not line.strip() or line.strip().startswith('#'): + elif not line.strip() or line.strip().startswith('#'): # echo all other lines sys.stdout.write(line) sys.stdout.flush() i_ += 1 From 1352dbb5d4a9c0a687e4ac798fa5be741b79d022 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Tue, 20 May 2025 15:58:37 -0400 Subject: [PATCH 24/36] fixed indent error introduced in last commit (ldas_setup) --- GEOSldas_App/ldas_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index b5bad5db..5efa7194 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -689,7 +689,7 @@ class LDASsetup: fin = open(inpfile, 'r') linenum = 0 for line in fin: - linenum += 1 + linenum += 1 line = line.strip() # blank line if not line: From a3c43126fb40a7258a4daf110cd106dc446c155d Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Wed, 21 May 2025 12:12:56 -0400 Subject: [PATCH 25/36] fixed py bugs from previous commit (ldas_setup) --- GEOSldas_App/ldas_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 5efa7194..00c9c268 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -229,7 +229,7 @@ class LDASsetup: self.rqdExeInp['MET_HINTERP'] = 0 self.landassim_dt = 10800 # seconds # make sure ADAS analysis window [minutes] is multiple of LANDASSIM_DT [seconds] - if self.varwindow % self.landassim_dt/60 == 0 : + if int(self.varwindow) % (self.landassim_dt/60) == 0 : self.rqdExeInp['LANDASSIM_DT'] = self.landassim_dt else : exit("Error. LANDASSIM_DT is inconsistent with ADAS analysis window.\n") From 5278ce012ca830fd90d0873c8d93511db56c1bc3 Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Wed, 21 May 2025 12:39:51 -0400 Subject: [PATCH 26/36] skip writing extra lines with #agcm=> or #ldas=> --- GEOSldas_App/ldas_setup | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 00c9c268..23ed67bc 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1795,17 +1795,14 @@ def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): if ( 5<=i_ and i_<=21) : # skip over lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited i_ +=1 continue - if '"GEOSagcm=>"' in line: # echo lines that contain "GEOSagcm=>" (w/ quotation marks) - sys.stdout.write(line) - elif '"GEOSldas=>"' in line: # echo lines that contain "GEOSldas=>" (w/ quotation marks) - sys.stdout.write(line) - elif use_rc_defaults in line: # process lines that contain string "use_rc_defaults" + if use_rc_defaults in line: # process lines that contain string "use_rc_defaults" line0 = line.split(use_rc_defaults)[1] sys.stdout.write(line0) - elif not line.strip() or line.strip().startswith('#'): # echo all other lines - sys.stdout.write(line) - sys.stdout.flush() - i_ += 1 + if not '=>' in line : + if not line.strip() or line.strip().startswith('#'): # echo all other lines + sys.stdout.write(line) + sys.stdout.flush() + i_ += 1 print () print () From 054ba569beb45ea213cc04123cfe0011d5cc54d7 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Wed, 21 May 2025 20:54:46 -0400 Subject: [PATCH 27/36] no exeinp for adas coupling --- GEOSldas_App/ldas_setup | 556 ++++++++++++++++++++-------------------- 1 file changed, 284 insertions(+), 272 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 23ed67bc..6727ed32 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -66,11 +66,6 @@ class LDASsetup: # ------ optSlurmInpKeys = ['job_name', 'qos', 'oserver_nodes', 'writers-per-node'] - # determine if LDAS should be coupled with ADAS - self.ladas_cpl = 0 # default is stand-alone (offline) LDAS - if cmdLineArgs['ladas_cpl'] != 'None' : - self.ladas_cpl = int(cmdLineArgs['ladas_cpl']) - # ------ # ./ldsetup.py sample ... # ------ @@ -80,7 +75,7 @@ class LDASsetup: # either: {'exeinp': False, 'batinp': True } # or: {'exeinp': True, 'batinp': False} if cmdLineArgs['exeinp']: - _printExeInputKeys(rqdExeInpKeys, self.ladas_cpl) + _produceExeInput() elif cmdLineArgs['batinp']: _printRmInputKeys( rqdRmInpKeys, optSlurmInpKeys) else: @@ -99,6 +94,7 @@ class LDASsetup: self.verbose = cmdLineArgs['verbose'] # command line args for coupled land-atm DAS (see "help" strings in parseCmdLine() for details) + self.ladas_cpl = cmdLineArgs['ladas_cpl'] self.nymdb = cmdLineArgs['nymdb'] self.nhmsb = cmdLineArgs['nhmsb'] self.agcm_res = cmdLineArgs['agcm_res'] @@ -137,19 +133,30 @@ class LDASsetup: self.perturb = 0 self.first_ens_id = 0 self.in_rstfile = None - self.in_tilefile = 'None' # default string - self.ens_id_width = 6 # _eXXXX + self.in_tilefile = None # default string + self.ens_id_width = 6 # _eXXXX self.bcs_dir_land = '' self.bcs_dir_geom = '' self.bcs_dir_landshared = '' self.tile_types = '' self.with_land = False self.with_landice = False + self.adas_expdir = '' # ------ # Read exe input file which is required to set up the dir # ------ - self.rqdExeInp = self._parseInputFile(cmdLineArgs['exeinpfile']) + if self.ladas_cpl is None: + self.ladas_cpl = 0 + else: + self.ladas_cpl = int(self.ladas_cpl) + + self.rqdExeInp = {} + if self.ladas_cpl == 0: + self.rqdExeInp = self._parseInputFile(cmdLineArgs['exeinpfile']) + else: + _produceExeInput(out_dict=self.rqdExeInp, ladas_cpl=self.ladas_cpl) + # verifing the required input if 'RESTART' not in self.rqdExeInp : self.rqdExeInp['RESTART'] = "1" @@ -157,99 +164,94 @@ class LDASsetup: if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) ==0 : rqdExeInpKeys = rqdExeInpKeys_rst - self.rqdExeInp['RESTART_ID'] = "none" - self.rqdExeInp['RESTART_DOMAIN'] = "none" - self.rqdExeInp['RESTART_PATH'] = "none" + self.rqdExeInp['RESTART_ID'] = 'None' + self.rqdExeInp['RESTART_DOMAIN'] = 'None' + self.rqdExeInp['RESTART_PATH'] = 'None' else: if self.rqdExeInp['RESTART'] =='G' : rqdExeInpKeys = rqdExeInpKeys_rst - self.rqdExeInp['RESTART_DOMAIN'] = "none" + self.rqdExeInp['RESTART_DOMAIN'] = 'None' else: - self.rqdExeInp['RESTART_ID'] = "none" - self.rqdExeInp['RESTART_DOMAIN'] = "none" - self.rqdExeInp['RESTART_PATH'] = "none" - # process command line args that may be useful independent of the value of self.ladas_cpl - if self.nymdb != 'None' and self.nhmsb != 'None' : - self.rqdExeInp['BEG_DATE'] = f"{self.nymdb} {self.nhmsb}" - if self.rstloc != 'None' : - rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' - assert os.path.isdir(rstloc_) # make sure rstloc_ is a valid directory - self.rstloc = os.path.abspath(rstloc_) - self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) - self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) + self.rqdExeInp['RESTART_ID'] = 'None' + self.rqdExeInp['RESTART_DOMAIN'] = 'None' + self.rqdExeInp['RESTART_PATH'] = 'None' ### check if ldas is coupled to adas; if so, set/overwrite input parameters accordingly - self.adas_expdir = '' if self.ladas_cpl > 0 : - # make sure all necessary command line arguments were supplied - if self.nymdb == 'None' : exit("Error. Must have command line arg nymdb for coupled land-atm DAS.\n") - if self.nhmsb == 'None' : exit("Error. Must have command line arg nhmsb for coupled land-atm DAS.\n") - if self.agcm_res == 'None' : exit("Error. Must have command line arg agcm_res for coupled land-atm DAS.\n") - if self.bcs_version == 'None' : exit("Error. Must have command line arg bcs_version for coupled land-atm DAS.\n") - if self.rstloc == 'None' : exit("Error. Must have command line arg rstloc for coupled land-atm DAS.\n") - if self.varwindow == 'None' : exit("Error. Must have command line arg varwindow for coupled land-atm DAS.\n") - if self.LDAS_nml_path == 'None' : exit("Error. Must have command line arg LDAS_nml_path for coupled land-atm DAS.\n") - if self.mwrtm_path == 'None' : exit("Error. Must have command line arg mwrtm_path for coupled land-atm DAS.\n") - - self.adas_expdir = os.path.dirname( self.exphome) - self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir - self.adas_expid = os.path.basename(self.adas_expdir) - self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' - if self.ladas_cpl == 1 : - # ldas coupled with determistic component of adas - self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' - self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' - self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' - self.nens = 24 # for now, hardwire nens for atm det - elif self.ladas_cpl == 2 : - # ldas coupled with ensemble component of adas - self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' - self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' - self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' - self.nens = 32 # for now, hardwire nens for atm ens - else : - exit("Error. Unknown value of self.ladas_cpl.\n") - self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens - self.first_ens_id = 1 - self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id - self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' - - # when coupled to ADAS, "BCS_PATH" EXCLUDE bcs version info - # hard-wired BCS_PATH for now - self.rqdExeInp['BCS_PATH'] = "/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles" - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'].rstrip('/') + '/' + self.bcs_version - if self.bcs_version == "Icarus-NLv3" : - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' - self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' - self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + # make sure all necessary command line arguments were supplied + assert self.nymdb is not None, "Error. Must have command line arg nymdb for coupled land-atm DAS.\n" + assert self.nhmsb is not None, "Error. Must have command line arg nhmsb for coupled land-atm DAS.\n" + assert self.agcm_res is not None, "Error. Must have command line arg agcm_res for coupled land-atm DAS.\n" + assert self.bcs_version is not None, "Error. Must have command line arg bcs_version for coupled land-atm DAS.\n" + assert self.rstloc is not None, "Error. Must have command line arg rstloc for coupled land-atm DAS.\n" + assert self.varwindow is not None, "Error. Must have command line arg varwindow for coupled land-atm DAS.\n" + assert self.LDAS_nml_path is not None, "Error. Must have command line arg LDAS_nml_path for coupled land-atm DAS.\n" + assert self.mwrtm_path is not None, "Error. Must have command line arg mwrtm_path for coupled land-atm DAS.\n" - # the following are not in default rqdExeInp list; hardwire for now - self.rqdExeInp['LAND_ASSIM'] = "YES" - self.rqdExeInp['MET_HINTERP'] = 0 - self.landassim_dt = 10800 # seconds - # make sure ADAS analysis window [minutes] is multiple of LANDASSIM_DT [seconds] - if int(self.varwindow) % (self.landassim_dt/60) == 0 : - self.rqdExeInp['LANDASSIM_DT'] = self.landassim_dt - else : - exit("Error. LANDASSIM_DT is inconsistent with ADAS analysis window.\n") - self.rqdExeInp['LANDASSIM_T0'] = "013000" # HHMMSS - jsgmt1 = "00000000" - jsgmt2 = hours_to_hhmmss(int(self.varwindow)/60) # convert minutes to HHMMSS - self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" - self.rqdExeInp['NUM_SGMT'] = 1 - self.rqdExeInp['FORCE_DTSTEP'] = 3600 - - # determine END_DATE = BEG_DATE + TIME_STEP_OF_ADAS_CYCLE - _beg_date = datetime.strptime( self.rqdExeInp['BEG_DATE'], "%Y%m%d %H%M%S") - _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) - _end_date = _beg_date + timedelta(hours=int(self.varwindow)/60) - - self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") - if self.LDAS_nml_path != 'None' : - self.rqdExeInp['NML_INPUT_PATH'] = self.LDAS_nml_path - if self.mwrtm_path != 'None' : - self.rqdExeInp['MWRTM_PATH'] = self.mwrtm_path + self.rqdExeInp['BEG_DATE'] = f"{self.nymdb} {self.nhmsb}" + rstloc_ = self.rstloc.rstrip('/') # remove trailing '/' + assert os.path.isdir(rstloc_) # make sure rstloc_ is a valid directory + self.rstloc = os.path.abspath(rstloc_) + self.rqdExeInp['RESTART_PATH'] = os.path.dirname( self.rstloc) + self.rqdExeInp['RESTART_ID'] = os.path.basename(self.rstloc) + + self.adas_expdir = os.path.dirname( self.exphome) + self.rqdExeInp['ADAS_EXPDIR'] = self.adas_expdir + self.adas_expid = os.path.basename(self.adas_expdir) + self.rqdExeInp['MET_TAG'] = self.adas_expid + '__bkg' + if self.ladas_cpl == 1 : + # ldas coupled with determistic component of adas + self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS' + self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/recycle/holdpredout' + self.rqdExeInp['ENSEMBLE_FORCING'] = 'NO' + self.nens = 24 # for now, hardwire nens for atm det + elif self.ladas_cpl == 2 : + # ldas coupled with ensemble component of adas + self.rqdExeInp['EXP_ID'] = self.adas_expid + '_LDAS4ens' + self.rqdExeInp['MET_PATH'] = self.adas_expdir + '/atmens/mem' + self.rqdExeInp['ENSEMBLE_FORCING'] = 'YES' + self.nens = 32 # for now, hardwire nens for atm ens + else : + exit("Error. Unknown value of self.ladas_cpl.\n") + self.rqdExeInp['NUM_LDAS_ENSEMBLE'] = self.nens + self.first_ens_id = 1 + self.rqdExeInp['FIRST_ENS_ID'] = self.first_ens_id + self.rqdExeInp['EXP_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + + # when coupled to ADAS, "BCS_PATH" EXCLUDE bcs version info + # hard-wired BCS_PATH for now + self.rqdExeInp['BCS_PATH'] = "/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles" + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'].rstrip('/') + '/' + self.bcs_version + if self.bcs_version == "Icarus-NLv3" : + self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH'] + '_new_layout' + self.rqdExeInp['BCS_RESOLUTION'] = 'CF'+ self.agcm_res +'x6C_CF' + self.agcm_res +'x6C' + self.rqdExeInp['RESTART_DOMAIN'] = 'CF'+ self.agcm_res +'x6C_GLOBAL' + + # the following are not in default rqdExeInp list; hardwire for now + self.rqdExeInp['LAND_ASSIM'] = "YES" + self.rqdExeInp['MET_HINTERP'] = 0 + self.landassim_dt = 10800 # seconds + # make sure ADAS analysis window [minutes] is multiple of LANDASSIM_DT [seconds] + if int(self.varwindow) % (self.landassim_dt/60) == 0 : + self.rqdExeInp['LANDASSIM_DT'] = self.landassim_dt + else : + exit("Error. LANDASSIM_DT is inconsistent with ADAS analysis window.\n") + self.rqdExeInp['LANDASSIM_T0'] = "013000" # HHMMSS + jsgmt1 = "00000000" + jsgmt2 = hours_to_hhmmss(int(self.varwindow)/60) # convert minutes to HHMMSS + self.rqdExeInp['JOB_SGMT'] = f"{jsgmt1} {jsgmt2}" + self.rqdExeInp['NUM_SGMT'] = 1 + self.rqdExeInp['FORCE_DTSTEP'] = 3600 + + # determine END_DATE = BEG_DATE + TIME_STEP_OF_ADAS_CYCLE + _beg_date = datetime.strptime( self.rqdExeInp['BEG_DATE'], "%Y%m%d %H%M%S") + _hours = int(self.rqdExeInp['JOB_SGMT'][ 9:11]) + _end_date = _beg_date + timedelta(hours=int(self.varwindow)/60) + + self.rqdExeInp['END_DATE'] = _end_date.strftime("%Y%m%d %H%M%S") + self.rqdExeInp['NML_INPUT_PATH'] = self.LDAS_nml_path + self.rqdExeInp['MWRTM_PATH'] = self.mwrtm_path # end if self.ladas_cpl > 0 @@ -549,8 +551,6 @@ class LDASsetup: self.in_tilefile = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_EASE/SMAP_EASEv2_M36/SMAP_EASEv2_M36_964x406.til' else: sys.exit('need to provide at least dummy files') - self.in_rstfile = None - self.in_tilefile = None # DEAL WITH mwRTM input from exec self.assim = True if self.rqdExeInp.get('LAND_ASSIM', 'NO').upper() == 'YES' and self.with_land else False @@ -582,8 +582,6 @@ class LDASsetup: inpDictFromFile = self._parseInputFile(cmdLineArgs['batinpfile']) if self.ladas_cpl > 0 : - if cmdLineArgs['account'] != 'None': - self.rqdRmInp['account'] = cmdLineArgs['account'] self.rqdRmInp['walltime'] = "01:00:00" self.rqdRmInp['ntasks_model'] = 120 self.rqdRmInp['ntasks-per-node'] = 46 # 46 works on Cascade Lake and Milan @@ -595,8 +593,6 @@ class LDASsetup: # checks on rqd rm inputs ## account and walltime should exist assert self.rqdRmInp['account'] - if cmdLineArgs['account'] != 'None': - self.rqdRmInp['account'] = cmdLineArgs['account'] assert self.rqdRmInp['walltime'] ## ntasks_model is a +ve integer _ntasks = int(self.rqdRmInp['ntasks_model']) @@ -604,6 +600,9 @@ class LDASsetup: self.rqdRmInp['ntasks_model'] = _ntasks _ntasks = None + if cmdLineArgs['account'] is not None: + self.rqdRmInp['account'] = cmdLineArgs['account'] + # print rqd rm inputs if self.verbose: print ('\n\nRequired inputs for resource manager:') @@ -1622,167 +1621,168 @@ def _printdict(d): # ----------------------------------------------------------------------------------- -def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): +def _produceExeInput(out_dict=None,ladas_cpl=0): """ Private method: print sample exe input """ + if ladas_cpl > 0: + assert out_dict is not None , " Need out_dict to hold the default parameters" + + # stand-alone (offline) LDAS: + # sample exeinp file includes placeholders for inputs that the user needs to provide + if ladas_cpl == 0: + print ('####################################################################################') + print ('# #') + print ('# REQUIRED INPUTS #') + print ('# #') + print ('# These inputs are needed to set up output dir structure. #') + print ('# #') + print ('####################################################################################') + print () + print ('############################################################') + print ('# #') + print ('# EXPERIMENT INFO #') + print ('# #') + print ('# Format for start/end times is yyyymmdd hhmmss. #') + print ('# #') + print ('############################################################') + print () + print ('EXP_ID:') + print ('EXP_DOMAIN:') + print ('NUM_LDAS_ENSEMBLE:') + print ('BEG_DATE:') + print ('END_DATE:') + print () + print ('############################################################') + print ('# #') + print ('# RESTART INFO #') + print ('# #') + print ('# (i) Select "RESTART" option: #') + print ('# #') + print ('# Use one of the following options if you *have* a #') + print ('# GEOSldas restart file: #') + print ('# #') + print ('# RESTART: 1 #') + print ('# YES, have restart file from GEOSldas #') + print ('# in SAME tile space (grid) with SAME boundary #') + print ('# conditions and SAME snow model parameter (WEMIN). #') + print ('# The restart domain can be for the same or #') + print ('# a larger one. #') + print ('# #') + print ('# RESTART: 2 #') + print ('# YES, have restart file from GEOSldas but #') + print ('# in a DIFFERENT tile space (grid) or with #') + print ('# DIFFERENT boundary conditions or DIFFERENT snow #') + print ('# model parameter (WEMIN). #') + print ('# Restart *must* be for the GLOBAL domain. #') + print ('# #') + print ('# Use one of the following options if you DO NOT have a #') + print ('# GEOSldas restart file #') + print ('# (works for global domain ONLY!): #') + print ('# #') + print ('# RESTART: 0 #') + print ('# Cold start from some old restart for Jan 1, 0z. #') + print ('# #') + print ('# RESTART: M #') + print ('# Re-tile from archived MERRA-2 restart file. #') + print ('# #') + print ('# -------------------------------------------------------- #') + print ('# IMPORTANT: #') + print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') + print ('# all cases. #') + print ('# -------------------------------------------------------- #') + print ('# #') + print ('# #') + print ('# (ii) Specify experiment ID/location of restart file: #') + print ('# #') + print ('# For RESTART=1 or RESTART=2: #') + print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') + print ('# restarts stored as follows: #') + print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') + print ('# #') + print ('# For RESTART=0 or RESTART=M: #') + print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') + print ('# and RESTART_DOMAIN. #') + print ('# #') + print ('############################################################') + print () + print ('RESTART:') + print ('#RESTART_ID:') + print ('#RESTART_PATH:') + print ('#RESTART_DOMAIN:') + print () + print ('############################################################') + print ('# #') + print ('# SURFACE METEOROLOGICAL FORCING #') + print ('# #') + print ('# Surface meteorological forcing time step is in seconds. #') + print ('# #') + print ('# NOTE: #') + print ('# When forcing is on cube-sphere (CS) grid, must use: #') + print ('# - Model tile space (BCS) derived from same CS grid. #') + print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') + print ('# #') + print ('# For more information, see: #') + print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') + print ('# #') + print ('############################################################') + print () + print ('MET_TAG:') + print ('MET_PATH:') + print ('FORCE_DTSTEP:') + print () + print ('############################################################') + print ('# #') + print ('# LAND BOUNDARY CONDITIONS (BCS) #') + print ('# #') + print ('# Path to and (atmospheric) resolution of BCS. #') + print ('# Path includes BCS_VERSION. #') + print ('# #') + print ('# For more information, see: #') + print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') + print ('# [..]/GEOSsurface_GridComp/Utils/Raster/make_bcs #') + print ('# #') + print ('############################################################') + print () + print ('BCS_PATH:') + print ('BCS_RESOLUTION:') + print () + print ('############################################################') + + # LDAS coupled to ADAS: + # exclude "required" inputs from sample exeinp file because they will be + # provided by the ADAS setup script (fvsetup) + + print ('####################################################################################') + print ('# #') + print ('# THE ABOVE PARAMETERS ARE NOT REQUIRED IF LDAS COUPLED WITH ADAS #') + print ('# #') + print ('# The ADAS setup script (fvsetup) provides EXP_ID, BEG_DATE, END_DATE, etc #') + print ('# #') + print ('####################################################################################') - if ladas_cpl == 0 : - - # stand-alone (offline) LDAS: - # sample exeinp file includes placeholders for inputs that the user needs to provide - - print ('####################################################################################') - print ('# #') - print ('# REQUIRED INPUTS #') - print ('# #') - print ('# These inputs are needed to set up output dir structure. #') - print ('# #') - print ('####################################################################################') - print () - print ('############################################################') - print ('# #') - print ('# EXPERIMENT INFO #') - print ('# #') - print ('# Format for start/end times is yyyymmdd hhmmss. #') - print ('# #') - print ('############################################################') - print () - print ('EXP_ID:') - print ('EXP_DOMAIN:') - print ('NUM_LDAS_ENSEMBLE:') - print ('BEG_DATE:') - print ('END_DATE:') - print () - print ('############################################################') - print ('# #') - print ('# RESTART INFO #') - print ('# #') - print ('# (i) Select "RESTART" option: #') - print ('# #') - print ('# Use one of the following options if you *have* a #') - print ('# GEOSldas restart file: #') - print ('# #') - print ('# RESTART: 1 #') - print ('# YES, have restart file from GEOSldas #') - print ('# in SAME tile space (grid) with SAME boundary #') - print ('# conditions and SAME snow model parameter (WEMIN). #') - print ('# The restart domain can be for the same or #') - print ('# a larger one. #') - print ('# #') - print ('# RESTART: 2 #') - print ('# YES, have restart file from GEOSldas but #') - print ('# in a DIFFERENT tile space (grid) or with #') - print ('# DIFFERENT boundary conditions or DIFFERENT snow #') - print ('# model parameter (WEMIN). #') - print ('# Restart *must* be for the GLOBAL domain. #') - print ('# #') - print ('# Use one of the following options if you DO NOT have a #') - print ('# GEOSldas restart file #') - print ('# (works for global domain ONLY!): #') - print ('# #') - print ('# RESTART: 0 #') - print ('# Cold start from some old restart for Jan 1, 0z. #') - print ('# #') - print ('# RESTART: M #') - print ('# Re-tile from archived MERRA-2 restart file. #') - print ('# #') - print ('# -------------------------------------------------------- #') - print ('# IMPORTANT: #') - print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') - print ('# all cases. #') - print ('# -------------------------------------------------------- #') - print ('# #') - print ('# #') - print ('# (ii) Specify experiment ID/location of restart file: #') - print ('# #') - print ('# For RESTART=1 or RESTART=2: #') - print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') - print ('# restarts stored as follows: #') - print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') - print ('# #') - print ('# For RESTART=0 or RESTART=M: #') - print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') - print ('# and RESTART_DOMAIN. #') - print ('# #') - print ('############################################################') - print () - print ('RESTART:') - print ('#RESTART_ID:') - print ('#RESTART_PATH:') - print ('#RESTART_DOMAIN:') - print () - print ('############################################################') - print ('# #') - print ('# SURFACE METEOROLOGICAL FORCING #') - print ('# #') - print ('# Surface meteorological forcing time step is in seconds. #') - print ('# #') - print ('# NOTE: #') - print ('# When forcing is on cube-sphere (CS) grid, must use: #') - print ('# - Model tile space (BCS) derived from same CS grid. #') - print ('# - Nearest-neighbor interpolation (MET_HINTERP: 0). #') - print ('# #') - print ('# For more information, see: #') - print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# #') - print ('############################################################') - print () - print ('MET_TAG:') - print ('MET_PATH:') - print ('FORCE_DTSTEP:') - print () - print ('############################################################') - print ('# #') - print ('# LAND BOUNDARY CONDITIONS (BCS) #') - print ('# #') - print ('# Path to and (atmospheric) resolution of BCS. #') - print ('# Path includes BCS_VERSION. #') - print ('# #') - print ('# For more information, see: #') - print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# [..]/GEOSsurface_GridComp/Utils/Raster/make_bcs #') - print ('# #') - print ('############################################################') - print () - print ('BCS_PATH:') - print ('BCS_RESOLUTION:') - print () - print ('############################################################') - - else : - - # LDAS coupled to ADAS: - # exclude "required" inputs from sample exeinp file because they will be - # provided by the ADAS setup script (fvsetup) - - print ('####################################################################################') - print ('# #') - print ('# THIS SAMPLE EXEINP FILE HAS BEEN CUSTOMIZED FOR THE COUPLED LAND-ATM DAS #') - print ('# #') - print ('# The ADAS setup script (fvsetup) provides EXP_ID, BEG_DATE, END_DATE, etc #') - print ('# #') - print ('####################################################################################') - - # end if ladas_cpl==0 # add defaults from GEOSldas_LDAS.rc - - _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory + + current_directory = os.path.dirname(__file__) + _fn = current_directory[0:-6]+'/etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory + lines = [] with open(_fn) as _f: i_ = 1 for line in _f: if ( i_ < 5 or i_ >10): # ignore lines 5-10 - may need to change if GEOSldas_LDAS.rc is edited - sys.stdout.write(line) - sys.stdout.flush() + if ladas_cpl == 0: + sys.stdout.write(line) + sys.stdout.flush() + else: + lines.append(line) i_ += 1 print () print () # add land model parameter defaults from GEOS_SurfaceGridComp.rc - - _fn = '../etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory + _fn = current_directory[0:-6]+'/etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory if ladas_cpl == 0 : use_rc_defaults = 'GEOSldas=>' # use defaults for LDAS @@ -1797,16 +1797,34 @@ def _printExeInputKeys(rqdExeInpKeys,ladas_cpl): continue if use_rc_defaults in line: # process lines that contain string "use_rc_defaults" line0 = line.split(use_rc_defaults)[1] - sys.stdout.write(line0) + if ladas_cpl == 0: + sys.stdout.write(line0) + sys.stdout.flush() + else: + lines.append(line0) if not '=>' in line : if not line.strip() or line.strip().startswith('#'): # echo all other lines - sys.stdout.write(line) - sys.stdout.flush() + if ladas_cpl == 0: + sys.stdout.write(line) + sys.stdout.flush() + else: + lines.append(line) i_ += 1 print () print () + if ladas_cpl > 0: + for line in lines: + line = line.strip() + if not line or line.startswith('#'): + continue + position = line.find('#') + if position>0: # strip out comment + line = line[:position] + key, val = line.split(":",1) + out_dict[key.strip()] =val.strip() + # ----------------------------------------------------------------------------------- def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): @@ -1879,14 +1897,7 @@ def parseCmdLine(): action='store_true', ) - ladas_cpl_help='land-atm DAS coupling mode: default=0 (not coupled); LDAS coupled with (1) ADAS deterministic member or (2) ADAS ensemble', - p_sample.add_argument( - '--ladas_cpl', - help=ladas_cpl_help, - type=str, default='None' - ) - # subparser: "setup" command p_setup = p_sub.add_parser( 'setup', @@ -1913,55 +1924,56 @@ def parseCmdLine(): # the following command line arguments, if present, take precedence over what # is specified in the exeinp and batinp files + ladas_cpl_help='land-atm DAS coupling mode: default=0 (not coupled); LDAS coupled with (1) ADAS deterministic member or (2) ADAS ensemble. Required when exeinp is dummy' p_setup.add_argument( '--ladas_cpl', help=ladas_cpl_help, - type=str, default='None' + type=str ) p_setup.add_argument( '--account', help='overwrites computing/sponsor account from batinp file', - type=str, default='None' + type=str ) p_setup.add_argument( '--nymdb', - help='overwrites date in BEG_DATE from exeinp file', - type=str, default='None' + help='overwrites date in BEG_DATE from exeinp file: yyyymmdd. Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--nhmsb', - help='overwrites time in BEG_DATE from exeinp file', - type=str, default='None' + help='overwrites time in BEG_DATE from exeinp file: hhmmss. Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--agcm_res', - help='AGCM resolution associated with boundary conditions', - type=str, default='None' + help='AGCM resolution associated with boundary conditions: xxxx (4 digits). Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--bcs_version', - help='boundary conditions version', - type=str, default='None' + help='boundary conditions version. Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--rstloc', - help='location of LDAS restarts (restart_path/restart_id)', - type=str, default='None' + help='location of LDAS restarts (restart_path/restart_id). Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--varwindow', - help='ADAS analysis window (minutes)', - type=str, default='None' + help='ADAS analysis window (minutes). Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--LDAS_nml_path', - help='path to LDAS (special) nml input files', - type=str, default='None' + help='path to LDAS (special) nml input files. Required when exeinp is dummy', + type=str ) p_setup.add_argument( '--mwrtm_path', - help='path to LDAS L-band microwave radiative transfer model (mwrtm) parameters ', - type=str, default='None' + help='path to LDAS L-band microwave radiative transfer model (mwrtm) parameters. Required when exeinp is dummy', + type=str ) From 8a8c1d63bb802cf22a4b2b70d82f83d0b5872480 Mon Sep 17 00:00:00 2001 From: Weiyuan Jiang Date: Thu, 22 May 2025 08:35:36 -0400 Subject: [PATCH 28/36] remove unnecessary message --- GEOSldas_App/ldas_setup | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 6727ed32..fc9a7702 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1749,22 +1749,8 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): print () print ('############################################################') - # LDAS coupled to ADAS: - # exclude "required" inputs from sample exeinp file because they will be - # provided by the ADAS setup script (fvsetup) - - print ('####################################################################################') - print ('# #') - print ('# THE ABOVE PARAMETERS ARE NOT REQUIRED IF LDAS COUPLED WITH ADAS #') - print ('# #') - print ('# The ADAS setup script (fvsetup) provides EXP_ID, BEG_DATE, END_DATE, etc #') - print ('# #') - print ('####################################################################################') - # add defaults from GEOSldas_LDAS.rc - - current_directory = os.path.dirname(__file__) _fn = current_directory[0:-6]+'/etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory lines = [] From df1b1f374f1c6332efd23019555e286c119ae3af Mon Sep 17 00:00:00 2001 From: saraqzhang Date: Thu, 22 May 2025 11:51:48 -0400 Subject: [PATCH 29/36] minor changes for ladas_cpl case --- GEOSldas_App/ldas_setup | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index fc9a7702..3069e3fd 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1205,22 +1205,23 @@ class LDASsetup: # if a file w/ the same name already exists at rundir # append 1,2,3 etc, to the filename ## exe inp file - exefilename = self.exeinpfile.rstrip('/').split('/')[-1] - newfilename = exefilename - _nens = self.nens - ctr = 0 - while os.path.isfile(self.rundir+'/'+newfilename): - ctr += 1 - newfilename = exefilename + '.%d' % ctr - shutil.copy(self.exeinpfile, self.rundir+'/'+newfilename) - ## bat inp file - batfilename = self.batinpfile.rstrip('/').split('/')[-1] - newfilename = batfilename - ctr = 0 - while os.path.isfile(self.rundir+'/'+newfilename): - ctr += 1 - newfilename = batfilename + '.%d' % ctr - shutil.copy(self.batinpfile, self.rundir+'/'+newfilename) + if self.ladas_cpl == 0 : + exefilename = self.exeinpfile.rstrip('/').split('/')[-1] + newfilename = exefilename + _nens = self.nens + ctr = 0 + while os.path.isfile(self.rundir+'/'+newfilename): + ctr += 1 + newfilename = exefilename + '.%d' % ctr + shutil.copy(self.exeinpfile, self.rundir+'/'+newfilename) + ## bat inp file + batfilename = self.batinpfile.rstrip('/').split('/')[-1] + newfilename = batfilename + ctr = 0 + while os.path.isfile(self.rundir+'/'+newfilename): + ctr += 1 + newfilename = batfilename + '.%d' % ctr + shutil.copy(self.batinpfile, self.rundir+'/'+newfilename) etcdir = self.blddirLn + '/etc' @@ -1752,7 +1753,7 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): # add defaults from GEOSldas_LDAS.rc current_directory = os.path.dirname(__file__) - _fn = current_directory[0:-6]+'/etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory + _fn = current_directory[0:-4]+'/etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory lines = [] with open(_fn) as _f: i_ = 1 @@ -1768,7 +1769,7 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): print () # add land model parameter defaults from GEOS_SurfaceGridComp.rc - _fn = current_directory[0:-6]+'/etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory + _fn = current_directory[0:-4]+'/etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory if ladas_cpl == 0 : use_rc_defaults = 'GEOSldas=>' # use defaults for LDAS From 4a1802eedef0a16a708a6554a41204596c6dadfa Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 22 May 2025 12:36:59 -0400 Subject: [PATCH 30/36] additional changes and cleanup for coupled land-atm DAS (ldas_setup): - cleaned up logic of processing resource manager inputs - reverted to relative paths for rc files in ./etc - documentation of new functionality - updated language about compute nodes in sample batinp file (removed Skylake, added Milan) - fixed indentation --- GEOSldas_App/ldas_setup | 144 +++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 61 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 3069e3fd..377bcbda 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -54,36 +54,47 @@ class LDASsetup: 'MINLON','MAXLON','MINLAT','MAXLAT','EXCLUDE_FILE','INCLUDE_FILE','MWRTM_PATH','GRIDNAME', 'ADAS_EXPDIR', 'BCS_RESOLUTION', 'TILE_FILE_FORMAT' ] - self.GEOS_SITE = "@GEOS_SITE@" # ------ # Required resource manager input fields # ------ - rqdRmInpKeys = ['account', 'walltime', 'ntasks_model', 'ntasks-per-node'] + rqdRmInpKeys = ['account', 'walltime', 'ntasks_model', 'ntasks-per-node'] # ------ # Optional resource manager input fields # ------ optSlurmInpKeys = ['job_name', 'qos', 'oserver_nodes', 'writers-per-node'] + + # =============================================================================================== + # # ------ - # ./ldsetup.py sample ... + # ./ldas_setup sample ... # ------ - if 'exeinp' in cmdLineArgs: - # sample sub-command - # by construction, we can have - # either: {'exeinp': False, 'batinp': True } - # or: {'exeinp': True, 'batinp': False} + # + # "sample" sub-command: + # '--exeinp' and '--batinp' are mutually exclusive command line arguments. + # Specifying one will set it to True and set the other one to False. + # That is, we can have either: {'exeinp': False, 'batinp': True } + # or: {'exeinp': True, 'batinp': False} + + if 'exeinp' in cmdLineArgs: # 'exeinp' is always present in "sample" mode. + if cmdLineArgs['exeinp']: _produceExeInput() elif cmdLineArgs['batinp']: _printRmInputKeys( rqdRmInpKeys, optSlurmInpKeys) else: raise Exception('unrecognized option') + # + # EXIT after completing "sample" sub-command sys.exit(0) + + # =============================================================================================== + # # ------ - # ./ldsetup.py setup ... + # ./ldas_setup setup ... # ------ # Instance variables self.exeinpfile = cmdLineArgs['exeinpfile'] @@ -569,7 +580,6 @@ class LDASsetup: self.has_vegopacity = True self.rqdExeInp['VEGOPACITY_FILE'] = vegopacity_file_ - # DEAL WITH optional input from exec # ------ # Read rm input file @@ -579,46 +589,43 @@ class LDASsetup: # ------ # re-using inpDictFromFile - inpDictFromFile = self._parseInputFile(cmdLineArgs['batinpfile']) - - if self.ladas_cpl > 0 : - self.rqdRmInp['walltime'] = "01:00:00" - self.rqdRmInp['ntasks_model'] = 120 - self.rqdRmInp['ntasks-per-node'] = 46 # 46 works on Cascade Lake and Milan - else : - # REQUIRED inputs - for key in rqdRmInpKeys: + if self.ladas_cpl == 0 : + inpDictFromFile = self._parseInputFile(cmdLineArgs['batinpfile']) + # REQUIRED inputs + for key in rqdRmInpKeys: self.rqdRmInp[key] = inpDictFromFile.pop(key) - # checks on rqd rm inputs - ## account and walltime should exist - assert self.rqdRmInp['account'] - assert self.rqdRmInp['walltime'] - ## ntasks_model is a +ve integer - _ntasks = int(self.rqdRmInp['ntasks_model']) - assert _ntasks>0 - self.rqdRmInp['ntasks_model'] = _ntasks - _ntasks = None + # checks on rqd rm inputs + ## account and walltime should exist + assert self.rqdRmInp['account'] + assert self.rqdRmInp['walltime'] + ## ntasks_model is a +ve integer + _ntasks = int(self.rqdRmInp['ntasks_model']) + assert _ntasks>0 + self.rqdRmInp['ntasks_model'] = _ntasks + _ntasks = None + + # OPTIONAL inputs + for key in inpDictFromFile: + assert key in optSlurmInpKeys, \ + 'unknown resource manager key [%s]' % key + self.optRmInp[key] = inpDictFromFile[key] + else : + self.rqdRmInp['account'] = cmdLineArgs['account'] + self.rqdRmInp['walltime'] = "01:00:00" + self.rqdRmInp['ntasks_model'] = 120 + self.rqdRmInp['ntasks-per-node'] = 46 # 46 works on Cascade Lake and Milan + - if cmdLineArgs['account'] is not None: - self.rqdRmInp['account'] = cmdLineArgs['account'] - # print rqd rm inputs + # print rm inputs if self.verbose: print ('\n\nRequired inputs for resource manager:') _printdict(self.rqdRmInp) - - # OPTIONAL inputs - for key in inpDictFromFile: - assert key in optSlurmInpKeys, \ - 'unknown resource manager key [%s]' % key - self.optRmInp[key] = inpDictFromFile[key] - - # print opt rm inputs - if self.verbose: print ('\n\nOptional inputs for resource manager:') _printdict(self.optRmInp) - + print ('\n\n') + # ------ # set top level directories # rundir, inpdir, outdir, blddir @@ -1201,11 +1208,11 @@ class LDASsetup: assert os.path.isdir(mydir), \ 'dir [%s] does not exist!' % mydir - # first copy ldsetup input files to rundir - # if a file w/ the same name already exists at rundir - # append 1,2,3 etc, to the filename - ## exe inp file - if self.ladas_cpl == 0 : + if self.ladas_cpl == 0: + # copy ldas_setup exeinp and batinp input files to rundir (for the record) + # if a file w/ the same name already exists at rundir + # append 1,2,3 etc, to the filename + ## exe inp file exefilename = self.exeinpfile.rstrip('/').split('/')[-1] newfilename = exefilename _nens = self.nens @@ -1223,6 +1230,8 @@ class LDASsetup: newfilename = batfilename + '.%d' % ctr shutil.copy(self.batinpfile, self.rundir+'/'+newfilename) + # ----------------------------------- + etcdir = self.blddirLn + '/etc' #defalt nml @@ -1624,13 +1633,19 @@ def _printdict(d): def _produceExeInput(out_dict=None,ladas_cpl=0): """ - Private method: print sample exe input + Private method: (1) Print sample exeinp file to stdout for offline GEOSldas setup: + _produceExeInput(). + *or* + (2) Create dictionary w/ default parameters from GEOSldas_LDAS.rc and + GEOS_SurfaceGridComp.rc for coupled land-atm DAS setup: + _produceExeInput(out_dict, ladas_cpl=[1,2]). """ + if ladas_cpl > 0: assert out_dict is not None , " Need out_dict to hold the default parameters" # stand-alone (offline) LDAS: - # sample exeinp file includes placeholders for inputs that the user needs to provide + # sample exeinp file includes placeholders for inputs that the user needs to provide if ladas_cpl == 0: print ('####################################################################################') print ('# #') @@ -1750,15 +1765,16 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): print () print ('############################################################') - + # end if ladas_cpl==0 + # add defaults from GEOSldas_LDAS.rc - current_directory = os.path.dirname(__file__) - _fn = current_directory[0:-4]+'/etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory + + _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from ./install directory lines = [] with open(_fn) as _f: i_ = 1 for line in _f: - if ( i_ < 5 or i_ >10): # ignore lines 5-10 - may need to change if GEOSldas_LDAS.rc is edited + if ( i_ < 5 or i_ >10): # ignore lines 5-10 - may need to change if GEOSldas_LDAS.rc is edited if ladas_cpl == 0: sys.stdout.write(line) sys.stdout.flush() @@ -1769,7 +1785,8 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): print () # add land model parameter defaults from GEOS_SurfaceGridComp.rc - _fn = current_directory[0:-4]+'/etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory + + _fn = '../etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from ./install directory if ladas_cpl == 0 : use_rc_defaults = 'GEOSldas=>' # use defaults for LDAS @@ -1826,10 +1843,10 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('# - account = computational project number') print ('# [At NCCS: Use command "getsponsor" to see available account number(s).]' ) print ('# - walltime = walltime requested; format is HH:MM:SS (hours/minutes/seconds)') - print ('# - ntasks_model = number of processors requested for the model (typically 112; output server is not included)') - print ('# - ntasks-per-node = number of tasks per node (typically 46 for cascade* and 40 for skylake nodes)') - print ('# [If >40, cascade nodes will be allocated, else cascade or skylake.]') - print ('# [*NCCS recommends <=46 cores per node on SCU16 (cascade) due to OS issues (as of 6 Oct 2021).]') + print ('# - ntasks_model = number of processors requested for the model (typically 126; output server is not included)') + print ('# - ntasks-per-node = number of tasks per node (typically 46 for Cascade Lake and 126 for Milan)') + print ('# [If >46, Milan nodes will be allocated, else Cascade Lake or Milan.]') + print ('# [NCCS recommends <=46 for Cascade Lake and <=126 for Milan.]') print ('#') for key in rqdRmInpKeys: print (key + ':') @@ -1854,17 +1871,22 @@ def parseCmdLine(): """ parse command line arguments and return a dict of options """ + #print 'in: parseCmdLine' p = argparse.ArgumentParser( description= \ - "Script to setup a GEOSldas experiment. The script requires "\ - "two (2) input files, one for the experiment inputs and the " \ - "other for the resource manager (SLURM). To create sample input " \ - "files use './ldas_setup sample -h'.", + "Script to setup a GEOSldas experiment. "\ + "To set up an *offline* GEOSldas experiment, the script requires "\ + "two (2) input files, one for the experiment inputs ('exeinp') and the "\ + "other for the (SLURM) resource manager ('batinp'). To create sample input "\ + "files use './ldas_setup sample -h'. "\ + "When used to set up a coupled land-atm DAS experiment, the script "\ + "*ignores* the input files, but dummy strings must still be specified. " formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) p_sub = p.add_subparsers(help='sub-command help') + # subparser: "sample" command p_sample = p_sub.add_parser( 'sample', From 08a80784f6039985dd9a175ee25bfc2aff12e48f Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 22 May 2025 12:55:37 -0400 Subject: [PATCH 31/36] fixed syntax error from previous commit (ldas_setup) --- GEOSldas_App/ldas_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 377bcbda..72cdec3c 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1881,7 +1881,7 @@ def parseCmdLine(): "other for the (SLURM) resource manager ('batinp'). To create sample input "\ "files use './ldas_setup sample -h'. "\ "When used to set up a coupled land-atm DAS experiment, the script "\ - "*ignores* the input files, but dummy strings must still be specified. " + "*ignores* the input files, but dummy strings must still be specified. ", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) p_sub = p.add_subparsers(help='sub-command help') From c3ca2d5f08366ba20b09a7c1dda486b17fd7f805 Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 22 May 2025 14:01:34 -0400 Subject: [PATCH 32/36] fix path to rc template files (ldas_setup) --- GEOSldas_App/ldas_setup | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 72cdec3c..7026b827 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -1767,9 +1767,15 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): # end if ladas_cpl==0 - # add defaults from GEOSldas_LDAS.rc + # add defaults from rc template files + + current_directory = os.path.dirname(__file__) # path where ldas_setup is + + # rc template files are in [current_directory]/../etc/ - _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from ./install directory + # add defaults from GEOSldas_LDAS.rc + + _fn = current_directory+'/../etc/GEOSldas_LDAS.rc' lines = [] with open(_fn) as _f: i_ = 1 @@ -1786,7 +1792,7 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): # add land model parameter defaults from GEOS_SurfaceGridComp.rc - _fn = '../etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from ./install directory + _fn = current_directory+'/../etc/GEOS_SurfaceGridComp.rc' if ladas_cpl == 0 : use_rc_defaults = 'GEOSldas=>' # use defaults for LDAS From 0f220cb7d946d85b9d377b5cfccd07e906463ada Mon Sep 17 00:00:00 2001 From: Rolf Reichle Date: Thu, 22 May 2025 18:21:42 -0400 Subject: [PATCH 33/36] cleaned up logic of processing defaults from GEOS_SurfaceGridComp.rc (ldas_setup) --- GEOSldas_App/ldas_setup | 56 ++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/GEOSldas_App/ldas_setup b/GEOSldas_App/ldas_setup index 7026b827..d1f332c8 100755 --- a/GEOSldas_App/ldas_setup +++ b/GEOSldas_App/ldas_setup @@ -271,7 +271,7 @@ class LDASsetup: # print rqd exe inputs if self.verbose: - print ('\nInputs from execfile:\n') + print ('\nInputs from exeinp file:\n') _printdict(self.rqdExeInp) self.tile_types = self.rqdExeInp.get('TILE_TYPES',"100").split() @@ -356,7 +356,6 @@ class LDASsetup: _difftime =timedelta(days = _years*365+_months*30+_days,hours = _hours,minutes=_mins,seconds=_seconds) _difftime = int(self.rqdExeInp['NUM_SGMT'])*_difftime - print (int(self.rqdExeInp['NUM_SGMT'])) _d = self.begDates[0] _endDate = self.endDates[0] _d = _d + _difftime @@ -1802,38 +1801,37 @@ def _produceExeInput(out_dict=None,ladas_cpl=0): with open(_fn) as _f : i_ = 1 for line in _f: - if ( 5<=i_ and i_<=21) : # skip over lines 5-21 - may need to change if GEOS_SurfaceGridComp.rc is edited - i_ +=1 + i_ +=1 + # skip over lines 5-21 (content does not apply after this processing) - may need to change if GEOS_SurfaceGridComp.rc is edited + if ( 5<=i_ and i_<=21 ) : continue - if use_rc_defaults in line: # process lines that contain string "use_rc_defaults" - line0 = line.split(use_rc_defaults)[1] - if ladas_cpl == 0: - sys.stdout.write(line0) - sys.stdout.flush() - else: - lines.append(line0) - if not '=>' in line : - if not line.strip() or line.strip().startswith('#'): # echo all other lines - if ladas_cpl == 0: - sys.stdout.write(line) - sys.stdout.flush() - else: - lines.append(line) - i_ += 1 + if ladas_cpl == 0: + # process lines that contain string "use_rc_defaults" + if use_rc_defaults in line: + line0 = line.split(use_rc_defaults)[1] + sys.stdout.write(line0) + sys.stdout.flush() + # echo blank lines and comment lines (except if they contain 'GEOSldas=>' or 'GEOSagcm=>') + if (not 'GEOSldas=>' in line) and (not 'GEOSagcm=>' in line) : + if (not line.strip()) or line.strip().startswith('#') : + sys.stdout.write(line) + sys.stdout.flush() + else: + # process lines that contain string "use_rc_defaults" + if use_rc_defaults in line: + line0 = line.split(use_rc_defaults)[1] + # strip out inline comment (if present) + position = line0.find('#') + if position>0: + line0 = line0[:position] + # extract key/value pair and add to dictionary + key, val = line0.split(":",1) + out_dict[key.strip()] = val.strip() + print () print () - if ladas_cpl > 0: - for line in lines: - line = line.strip() - if not line or line.startswith('#'): - continue - position = line.find('#') - if position>0: # strip out comment - line = line[:position] - key, val = line.split(":",1) - out_dict[key.strip()] =val.strip() # ----------------------------------------------------------------------------------- From 135445913fcf3d42cfd893c824bc783b4f805dab Mon Sep 17 00:00:00 2001 From: Rolf Reichle <54944691+gmao-rreichle@users.noreply.github.com> Date: Tue, 27 May 2025 16:01:38 -0400 Subject: [PATCH 34/36] Update CHANGELOG.md --- CHANGELOG.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcea00fb..de6e786c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Added more default settings and command line arguments for integrated land-atm DAS setup -- Added functionality for model-based QC of MODIS SCF observations using soil layer 1 temperature. -- Added functionality to simulate landice tiles. -- Added functionality to read nc4-formatted tile file. - ### Changed ### Fixed @@ -26,6 +21,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ----------------------------- +## [v3.0.0] - 2025-05-28 + +- 0-diff vs. v2.0.0. + +### Added + +- Added functionality to simulate landice tiles ([PR #18](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/18)). +- Added functionality to read nc4-formatted tile file ([PR #18](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/18)). +- Added model-based QC of (MODIS) snow cover area fraction observations using layer-1 soil temperature ([PR #96](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/96)). +- Added default settings and command line args for coupled land-atm DAS ([PR #94](https://github.com/GEOS-ESM/GEOSldas_GridComp/pull/94)). + +------------------------------ + ## [v2.0.0] - 2025-04-15 - 0-diff vs. v1.1.0. From 52c4c95fa8b4a30642457f00a40e4b59173dd2d9 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Wed, 28 May 2025 07:17:00 -0400 Subject: [PATCH 35/36] Fix up CI --- .circleci/config.yml | 6 +++--- .github/workflows/workflow.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b3975f06..7c025b9d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,11 +1,11 @@ version: 2.1 # Anchors in case we need to override the defaults from the orb -#baselibs_version: &baselibs_version v7.17.0 -#bcs_version: &bcs_version v11.4.0 +#baselibs_version: &baselibs_version v7.33.0 +#bcs_version: &bcs_version v11.6.0 orbs: - ci: geos-esm/circleci-tools@2 + ci: geos-esm/circleci-tools@4 workflows: build-test: diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 9ae989ef..060c4b41 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -22,7 +22,7 @@ jobs: if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" runs-on: ubuntu-24.04 container: - image: gmao/ubuntu24-geos-env:v7.32.0-intelmpi_2021.13-ifort_2021.13 + image: gmao/ubuntu24-geos-env:v7.33.0-intelmpi_2021.13-ifort_2021.13 env: OMPI_ALLOW_RUN_AS_ROOT: 1 @@ -78,7 +78,7 @@ jobs: if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" runs-on: ubuntu-24.04 container: - image: gmao/ubuntu24-geos-env-mkl:v7.32.0-openmpi_5.0.5-gcc_14.2.0 + image: gmao/ubuntu24-geos-env-mkl:v7.33.0-openmpi_5.0.5-gcc_14.2.0 env: OMPI_ALLOW_RUN_AS_ROOT: 1 From 7e64aa43becbfa1019539569b6489ab70e3058b4 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Wed, 28 May 2025 11:31:57 -0400 Subject: [PATCH 36/36] Fix up github CI --- .github/workflows/workflow.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 060c4b41..20796af2 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -56,9 +56,11 @@ jobs: mepo clone --partial blobless mepo status + - name: Debug PR branch + run: echo "PR is coming from ${{ github.event.pull_request.head.ref }}" + - name: Update other branches - if: - "!contains('refs/heads/main,refs/heads/develop', github.ref)" + if: ${{ github.event.pull_request.head.ref != 'main' && github.event.pull_request.head.ref != 'develop' }} run: | mepo checkout-if-exists ${GITHUB_HEAD_REF} mepo status @@ -112,9 +114,11 @@ jobs: mepo clone --partial blobless mepo status + - name: Debug PR branch + run: echo "PR is coming from ${{ github.event.pull_request.head.ref }}" + - name: Update other branches - if: - "!contains('refs/heads/main,refs/heads/develop', github.ref)" + if: ${{ github.event.pull_request.head.ref != 'main' && github.event.pull_request.head.ref != 'develop' }} run: | mepo checkout-if-exists ${GITHUB_HEAD_REF} mepo status