Skip to content
Merged
Changes from 2 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
888cca4
add setting defaults and more commdline options for ladas
saraqzhang Apr 25, 2025
07cde3d
additional edit for integrated configuration of land-atm DAS (ldas_se…
gmao-rreichle May 2, 2025
5bdce17
update input strings for agcm_res
saraqzhang May 2, 2025
29f77d8
add land BCs version input for ladas
saraqzhang May 5, 2025
a1a2533
cleanup of command line args for land-atm DAS config (ldas_setup)
gmao-rreichle May 6, 2025
2443b5a
updated CHANGELOG.md
gmao-rreichle May 6, 2025
7742280
changed handling of N_ens for coupled land-atm DAS setup (ldas_setup)
gmao-rreichle May 6, 2025
8a7c7fc
add README on construction of exeinp.txt for LADAS
saraqzhang May 6, 2025
01f0f63
minor cleanup as suggested by Weiyuan (ldas_setup)
gmao-rreichle May 7, 2025
f07f2e4
additional cleanup as suggested by Weiyuan for integrated land-atm DA…
gmao-rreichle May 7, 2025
0ec5846
change handling of BCS_PATH in setup of coupled land-atm DAS (ldas_se…
gmao-rreichle May 7, 2025
ab9c3c3
exclude AGCM defaults of GEOS_SurfaceGridComp.rc from sample exeinp f…
gmao-rreichle May 7, 2025
ea03973
further changes in setting exeinp & batinp variables
saraqzhang May 13, 2025
11dca45
minor cleanup to improve readability (ldas_setup)
gmao-rreichle May 13, 2025
7f115d9
additional changes and cleanup for integrated land-atm DAS config (ld…
gmao-rreichle May 13, 2025
ef43e7e
additional commandline inputs for ladas
saraqzhang May 15, 2025
7a023c9
minor edit insert adas_cyc input in JOB_SGMT
saraqzhang May 16, 2025
21e3584
Merge branch 'develop' into feature/saraqzhang/setupfunc4ladas
weiyuan-jiang May 19, 2025
86056e5
fixed errors in most recent merge (conflict resolution); white-space …
gmao-rreichle May 19, 2025
14f5186
remove README.exeinp.txt.forladas (no longer needed)
gmao-rreichle May 19, 2025
ae2717e
edits of previous commit (ldas_setup):
gmao-rreichle May 20, 2025
8dbd52a
edits on varwindow, walltime and nml path default
saraqzhang May 20, 2025
d36c72c
for coupled land-atm DAS, ensure consistency between LANDASSIM_DT and…
gmao-rreichle May 20, 2025
29a2b3c
clean up processing of defaults from GEOS_SurfaceGridComp.rc (ldas_se…
gmao-rreichle May 20, 2025
1352dbb
fixed indent error introduced in last commit (ldas_setup)
gmao-rreichle May 20, 2025
a3c4312
fixed py bugs from previous commit (ldas_setup)
gmao-rreichle May 21, 2025
5278ce0
skip writing extra lines with #agcm=> or #ldas=>
saraqzhang May 21, 2025
054ba56
no exeinp for adas coupling
weiyuan-jiang May 22, 2025
8a8c1d6
remove unnecessary message
weiyuan-jiang May 22, 2025
df1b1f3
minor changes for ladas_cpl case
saraqzhang May 22, 2025
4a1802e
additional changes and cleanup for coupled land-atm DAS (ldas_setup):
gmao-rreichle May 22, 2025
08a8078
fixed syntax error from previous commit (ldas_setup)
gmao-rreichle May 22, 2025
c3ca2d5
fix path to rc template files (ldas_setup)
gmao-rreichle May 22, 2025
0f220cb
cleaned up logic of processing defaults from GEOS_SurfaceGridComp.rc …
gmao-rreichle May 22, 2025
3d9121e
Merge branch 'develop' into feature/saraqzhang/setupfunc4ladas (manua…
gmao-rreichle May 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 136 additions & 68 deletions GEOSldas_App/ldas_setup
Original file line number Diff line number Diff line change
Expand Up @@ -70,59 +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.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
Expand Down Expand Up @@ -152,32 +155,79 @@ 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['ladas_cpl'] != 'None' :
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
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:
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
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.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0))
self.adas_expdir =''
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
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'
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'
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))
# 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.perturb = int(self.rqdExeInp.get('PERTURBATIONS',0))
if self.nens > 1:
self.perturb = 1
Expand Down Expand Up @@ -234,12 +284,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])
Expand Down Expand Up @@ -671,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
Expand Down Expand Up @@ -1061,6 +1105,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)
Expand Down Expand Up @@ -1560,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 #')
Expand All @@ -1591,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 ('# #')
Expand Down Expand Up @@ -1697,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
Expand All @@ -1706,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',
Expand All @@ -1723,21 +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(
'--ladas_cpl',
help='specifies LDAS/ADAS coupling mode: (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',
type=str, default='None'
)
p_setup.add_argument(
'--rstdir',
help='specifies LDAS restart dir (exp path/exp id)',
type=str, default='None'
)

p_setup.add_argument(
'--runmodel',
help='Obsolete.',
Expand Down
Loading