Skip to content

Commit

Permalink
Merge branch 'develop' into feature/gen_proto
Browse files Browse the repository at this point in the history
  • Loading branch information
CoryMartin-NOAA committed May 12, 2023
2 parents 89ffbc8 + 8c2706e commit 0949755
Show file tree
Hide file tree
Showing 22 changed files with 264 additions and 407 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ fv3-jedi-data/
fv3-jedi-lm/
gsibec/
gsw/
icepack/
/ioda/
ioda-data/
iodaconv/
Expand Down
4 changes: 2 additions & 2 deletions scripts/exgdas_global_marine_analysis_chkpt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ mom6_iau_incr=${DATA}/inc.nc
# prepare nsst yaml
if [ $DO_MERGENSST = "YES" ]; then
cat > nsst.yaml << EOF
sfc_fcst: ${ROTDIR}/${GDUMP}.${gPDY}/${gcyc}/atmos/${GPREFIX}sfcf006.nc
sfc_ana: ${COMOUT}/../atmos/${APREFIX}sfcanl.nc
sfc_fcst: ${COM_ATMOS_HISTORY_PREV}/${GPREFIX}sfcf006.nc
sfc_ana: ${COM_ATMOS_ANALYSIS}/${APREFIX}sfcanl.nc
nlayers: 5
EOF

Expand Down
96 changes: 55 additions & 41 deletions scripts/exgdas_global_marine_analysis_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,71 +23,85 @@
import shutil
import logging
from datetime import datetime, timedelta
import ufsda
from pygw.file_utils import FileHandler


# TODO: Move this somewhere else?
def list_all_files(dir_in, dir_out, wc='*', fh_list=[]):
files = glob.glob(os.path.join(dir_in, wc))
for file_src in files:
file_dst = os.path.join(dir_out, os.path.basename(file_src))
fh_list.append([file_src, file_dst])
return fh_list


# set up logger
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
logging.info(f"---------------- Copy from RUNDIR to COMOUT")

comout = os.getenv('COMOUT')
comoutice = os.getenv('COMOUTice')
com_ocean_analysis = os.getenv('COM_OCEAN_ANALYSIS')
com_ice_restart = os.getenv('COM_ICE_RESTART')
anl_dir = os.getenv('DATA')
cdate = os.getenv('CDATE')
pdy = os.getenv('PDY')
staticsoca_dir = os.getenv('SOCA_INPUT_FIX_DIR')
cdump = os.getenv('CDUMP')
# TODO: this cycle math does the job, but datetime might be safer
RUN = os.getenv('CDUMP')
cyc = str(os.getenv('cyc')).zfill(2)
bcyc = str((int(cyc) - 3) % 24).zfill(2)
gcyc = str((int(cyc) - 6) % 24).zfill(2) # previous cycle
bdatedt = datetime.strptime(cdate, '%Y%m%d%H') - timedelta(hours=3)
bdate = datetime.strftime(bdatedt, '%Y-%m-%dT%H:00:00Z')

# Make a copy the IAU increment
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'inc.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.ocninc.nc'))
post_file_list = []

# Copy of the ioda output files, as is for now
ufsda.disk_utils.copytree(os.path.join(anl_dir, 'diags'),
os.path.join(comout, 'diags'))
# Make a copy the IAU increment
post_file_list.append([os.path.join(anl_dir, 'inc.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocninc.nc')])

# Copy of the diagonal of the background error for the cycle
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'ocn.bkgerr_stddev.incr.' + bdate + '.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.ocn.bkgerr_stddev.nc'))
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'ice.bkgerr_stddev.incr.' + bdate + '.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.ice.bkgerr_stddev.nc'))
post_file_list.append([os.path.join(anl_dir, f'ocn.bkgerr_stddev.incr.{bdate}.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocn.bkgerr_stddev.nc')])
post_file_list.append([os.path.join(anl_dir, f'ice.bkgerr_stddev.incr.{bdate}.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ice.bkgerr_stddev.nc')])

# Copy the ice and ocean increments
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'Data', 'ocn.3dvarfgat_pseudo.incr.' + bdate + '.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.ocn.incr.nc'))
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'Data', 'ice.3dvarfgat_pseudo.incr.' + bdate + '.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.ice.incr.nc'))

# Copy the localization and correlation operators
ufsda.disk_utils.copytree(os.path.join(anl_dir, 'bump'),
os.path.join(comout, 'bump'))
post_file_list.append([os.path.join(anl_dir, 'Data', f'ocn.3dvarfgat_pseudo.incr.{bdate}.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocn.incr.nc')])
post_file_list.append([os.path.join(anl_dir, 'Data', f'ice.3dvarfgat_pseudo.incr.{bdate}.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ice.incr.nc')])

# Copy DA grid (computed for the start of the window)
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'soca_gridspec.nc'),
os.path.join(comout, cdump + '.t' + bcyc + 'z.ocngrid.nc'))
post_file_list.append([os.path.join(anl_dir, 'soca_gridspec.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{bcyc}z.ocngrid.nc')])

# Copy the analysis at the start of the window
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'Data', 'ocn.3dvarfgat_pseudo.an.' + bdate + '.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.ocnana.nc'))
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'Data', 'ice.3dvarfgat_pseudo.an.' + bdate + '.nc'),
os.path.join(comout, cdump + '.t' + cyc + 'z.iceana.nc'))
post_file_list.append([os.path.join(anl_dir, 'Data', f'ocn.3dvarfgat_pseudo.an.{bdate}.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocnana.nc')])
post_file_list.append([os.path.join(anl_dir, 'Data', f'ice.3dvarfgat_pseudo.an.{bdate}.nc'),
os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.iceana.nc')])

# Copy the CICE analysis restart
cdateice = pdy + '.' + cyc + '0000'
ufsda.disk_utils.copyfile(os.path.join(anl_dir, 'Data', cdateice + '.cice_model.res.nc'),
os.path.join(comoutice, 'RESTART', cdate + '.cice_model_anl.res.nc'))

# Copy logs
ufsda.mkdir(os.path.join(comout, 'logs'))
for file in glob.glob(os.path.join(anl_dir, '*.out')):
ufsda.disk_utils.copyfile(file, os.path.join(comout, 'logs'))

# Copy var.yaml
ufsda.mkdir(os.path.join(comout, 'yaml'))
for file in glob.glob(os.path.join(anl_dir, '*.yaml')):
ufsda.disk_utils.copyfile(file, os.path.join(comout, 'yaml'))
post_file_list.append([os.path.join(anl_dir, 'Data', f'{cdateice}.cice_model.res.nc'),
os.path.join(com_ice_restart, f'{cdate}.cice_model_anl.res.nc')])

FileHandler({'copy': post_file_list}).sync()

# create COM sub-directories
FileHandler({'mkdir': [os.path.join(com_ocean_analysis, 'diags'),
os.path.join(com_ocean_analysis, 'bump'),
os.path.join(com_ocean_analysis, 'yaml')]}).sync()

# ioda output files
fh_list = list_all_files(os.path.join(anl_dir, 'diags'),
os.path.join(com_ocean_analysis, 'diags'))

# localization and correlation operators
fh_list = list_all_files(os.path.join(anl_dir, 'bump'),
os.path.join(com_ocean_analysis, 'bump'), fh_list=fh_list)

# yaml configurations
fh_list = list_all_files(os.path.join(anl_dir),
os.path.join(com_ocean_analysis, 'yaml'), wc='*.yaml', fh_list=fh_list)

FileHandler({'copy': fh_list}).sync()
132 changes: 75 additions & 57 deletions scripts/exgdas_global_marine_analysis_prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from pygw.attrdict import AttrDict
from pygw.template import Template, TemplateConstants
from pygw.yaml_file import YAMLFile

from pygw.file_utils import FileHandler

# set up logger
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
Expand Down Expand Up @@ -138,6 +138,7 @@ def gen_bkg_list(bkg_path, out_path, window_begin=' ', yaml_name='bkg.yaml', ice
test_hist_date(os.path.join(bkg_path, ocn_filename_ic), bkg_date) # assert date of the history file is correct

# Copy/process backgrounds and generate background yaml list
bkg_list_src_dst = []
bkg_list = []
for bkg in files:

Expand All @@ -158,12 +159,12 @@ def gen_bkg_list(bkg_path, out_path, window_begin=' ', yaml_name='bkg.yaml', ice
# Process the CICE history file so they can be read by soca/fms
# TODO: Add date check of the cice history
# TODO: bkg_path should be 1 level up
cice_hist2fms(os.path.join(bkg_path, '..', 'ice', ice_filename),
cice_hist2fms(os.path.join(os.getenv('COM_ICE_HISTORY_PREV'), ice_filename),
os.path.join(out_path, agg_ice_filename))

# copy ocean bkg to out_path
ufsda.disk_utils.copyfile(os.path.join(bkg_path, ocn_filename),
os.path.join(out_path, ocn_filename))
# prepare list of ocean bkg to be copied to RUNDIR
bkg_list_src_dst.append([os.path.join(bkg_path, ocn_filename),
os.path.join(out_path, ocn_filename)])

bkg_dict = {'date': bkg_date.strftime('%Y-%m-%dT%H:%M:%SZ'),
'basename': './bkg/',
Expand All @@ -173,9 +174,14 @@ def gen_bkg_list(bkg_path, out_path, window_begin=' ', yaml_name='bkg.yaml', ice
'remap_filename': './bkg/'+ocn_filename_ic}
bkg_date = bkg_date + timedelta(hours=dt_pseudo) # TODO: make the bkg interval a configurable
bkg_list.append(bkg_dict)

# save pseudo model yaml configuration
f = open(yaml_name, 'w')
yaml.dump(bkg_list[1:], f, sort_keys=False, default_flow_style=False)

# copy ocean backgrounds to RUNDIR
FileHandler({'copy': bkg_list_src_dst}).sync()


def find_bkgerr(input_date, domain):
"""
Expand All @@ -200,31 +206,25 @@ def find_bkgerr(input_date, domain):

logging.info(f"---------------- Setup runtime environement")

comout = os.getenv('COMOUT')
comin_obs = os.getenv('COMIN_OBS')
comin_obs = os.getenv('COMIN_OBS') # R2D2 DB for now
anl_dir = os.getenv('DATA')
staticsoca_dir = os.getenv('SOCA_INPUT_FIX_DIR')

# create analysis directory for files
ufsda.mkdir(anl_dir)

# create output directory for obs
diags = os.path.join(anl_dir, 'diags')
ufsda.mkdir(diags)

# create output directory for obs
bkg_dir = os.path.join(anl_dir, 'bkg')
ufsda.mkdir(bkg_dir)

# create output directory for soca DA
anl_out = os.path.join(anl_dir, 'Data')
ufsda.mkdir(anl_out)
# create analysis directories
diags = os.path.join(anl_dir, 'diags') # output dir for soca DA obs space
obs_in = os.path.join(anl_dir, 'obs') # input " "
bkg_dir = os.path.join(anl_dir, 'bkg') # ice and ocean backgrounds
anl_out = os.path.join(anl_dir, 'Data') # output dir for soca DA
FileHandler({'mkdir': [anl_dir, diags, obs_in, bkg_dir, anl_out]}).sync()

# Variables of convenience
half_assim_freq = timedelta(hours=int(os.getenv('assim_freq'))/2)
window_begin = datetime.strptime(os.getenv('PDY')+os.getenv('cyc'), '%Y%m%d%H') - half_assim_freq
window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ')
fcst_begin = datetime.strptime(os.getenv('PDY')+os.getenv('cyc'), '%Y%m%d%H')
RUN = os.getenv('RUN')
cyc = os.getenv('cyc')
PDY = os.getenv('PDY')

################################################################################
# fetch observations
Expand All @@ -235,17 +235,34 @@ def find_bkgerr(input_date, domain):
ufsda.r2d2.setup(r2d2_config_yaml=os.path.join(anl_dir, 'r2d2_config.yaml'), shared_root=comin_obs)

# create config dict from runtime env
envconfig = ufsda.misc_utils.get_env_config(component='soca')
stage_cfg = YAMLFile(path=os.path.join(gdas_home,
'parm',
'templates',
'stage.yaml'))
envconfig = {'window_begin': f"{window_begin.strftime('%Y-%m-%dT%H:%M:%SZ')}",
'r2d2_obs_src': os.getenv('R2D2_OBS_SRC'),
'r2d2_obs_dump': os.getenv('R2D2_OBS_DUMP'),
'r2d2_obs_db': os.getenv('R2D2_OBS_DB'),
'ATM_WINDOW_BEGIN': window_begin_iso,
'ATM_WINDOW_LENGTH': f"PT{os.getenv('assim_freq')}H"}
stage_cfg = YAMLFile(path=os.path.join(gdas_home, 'parm', 'templates', 'stage.yaml'))
stage_cfg = Template.substitute_structure(stage_cfg, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get)
stage_cfg = Template.substitute_structure(stage_cfg, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get)
stage_cfg['r2d2_obs_out'] = os.getenv('COM_OBS')

# stage observations from R2D2 to COMIN_OBS and then link to analysis subdir
# stage observations from R2D2 COMIN_OBS to COM_OBS
ufsda.stage.obs(stage_cfg)

# get the list of observations
obs_files = []
for ob in stage_cfg['observations']['observers']:
obs_files.append(f"{RUN}.t{cyc}z.{ob['obs space']['name'].lower()}.{PDY}{cyc}.nc4")
obs_list = []

# copy obs from COM_OBS to DATA/obs
for obs_file in obs_files:
logging.info(f"******* {obs_file}")
obs_src = os.path.join(os.getenv('COM_OBS'), obs_file)
obs_dst = os.path.join(os.path.abspath(obs_in), obs_file)
obs_list.append([obs_src, obs_dst])
FileHandler({'copy': obs_list}).sync()

################################################################################
# stage static files

Expand All @@ -256,26 +273,25 @@ def find_bkgerr(input_date, domain):
# stage background error files

logging.info(f"---------------- Stage static files")
bkgerr_list = []
for domain in ['ocn', 'ice']:
fname_stddev = find_bkgerr(pytz.utc.localize(window_begin, is_dst=None), domain=domain)
fname_out = domain+'.bkgerr_stddev.incr.'+window_begin_iso+'.nc'
ufsda.disk_utils.copyfile(fname_stddev, os.path.join(stage_cfg['stage_dir'], fname_out))
bkgerr_list.append([fname_stddev, fname_out])
FileHandler({'copy': bkgerr_list}).sync()

################################################################################
# prepare JEDI yamls

logging.info(f"---------------- Generate JEDI yaml files")

################################################################################
# link yaml for grid generation
# copy yaml for grid generation

gridgen_yaml_src = os.path.abspath(os.path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml'))
gridgen_yaml_dst = os.path.abspath(os.path.join(stage_cfg['stage_dir'], 'gridgen.yaml'))
FileHandler({'copy': [[gridgen_yaml_src, gridgen_yaml_dst]]}).sync()

gridgen_yaml = os.path.join(gdas_home,
'parm',
'soca',
'gridgen',
'gridgen.yaml')
ufsda.disk_utils.symlink(gridgen_yaml,
os.path.join(stage_cfg['stage_dir'], 'gridgen.yaml'))

################################################################################
# generate YAML file for parametric diag of B
Expand All @@ -292,15 +308,11 @@ def find_bkgerr(input_date, domain):
config.save(berr_yaml)

################################################################################
# link yaml for decorrelation length scales
# copy yaml for decorrelation length scales

corscales_yaml = os.path.join(gdas_home,
'parm',
'soca',
'berror',
'soca_setcorscales.yaml')
ufsda.disk_utils.symlink(corscales_yaml,
os.path.join(stage_cfg['stage_dir'], 'soca_setcorscales.yaml'))
corscales_yaml_src = os.path.join(gdas_home, 'parm', 'soca', 'berror', 'soca_setcorscales.yaml')
corscales_yaml_dst = os.path.join(stage_cfg['stage_dir'], 'soca_setcorscales.yaml')
FileHandler({'copy': [[corscales_yaml_src, corscales_yaml_dst]]}).sync()

################################################################################
# generate yaml for bump/nicas (used for correlation and/or localization)
Expand Down Expand Up @@ -357,7 +369,7 @@ def find_bkgerr(input_date, domain):
'soca',
'variational',
'3dvarfgat.yaml')
gen_bkg_list(bkg_path=os.getenv('COMIN_GES'),
gen_bkg_list(bkg_path=os.getenv('COM_OCEAN_HISTORY_PREV'),
out_path=bkg_dir,
window_begin=window_begin,
yaml_name='bkg_list.yaml')
Expand Down Expand Up @@ -387,10 +399,9 @@ def find_bkgerr(input_date, domain):

# make a copy of the CICE6 restart
rst_date = fcst_begin.strftime('%Y%m%d.%H%M%S')
ice_rst = os.path.join(os.getenv('COMIN_GES'), '..', 'ice', 'RESTART',
rst_date+'.cice_model.res.nc')
ice_rst = os.path.join(os.getenv('COM_ICE_RESTART_PREV'), f'{rst_date}.cice_model.res.nc')
ice_rst_ana = os.path.join(anl_out, rst_date+'.cice_model.res.nc')
ufsda.disk_utils.copyfile(ice_rst, ice_rst_ana)
FileHandler({'copy': [[ice_rst, ice_rst_ana]]}).sync()

# write the two seaice analysis to model change of variable yamls
varchgyamls = ['soca_2cice_arctic.yaml', 'soca_2cice_antarctic.yaml']
Expand All @@ -408,26 +419,33 @@ def find_bkgerr(input_date, domain):
for varchgyaml in varchgyamls:
soca2cice_cfg['template'] = os.path.join(gdas_home, 'parm', 'soca', 'varchange', varchgyaml)
f = open('tmp.yaml', 'w')
# TODO: use YAMLFile instead
yaml.dump(soca2cice_cfg, f, sort_keys=False, default_flow_style=False)
ufsda.genYAML.genYAML('tmp.yaml', output=varchgyaml)

################################################################################
# links of convenience
RUN = os.getenv('RUN')
mom_ic = glob.glob(os.path.join(bkg_dir, f'{RUN}.*.ocnf003.nc'))[0]
ufsda.disk_utils.symlink(mom_ic, os.path.join(anl_dir, 'INPUT', 'MOM.res.nc'))

cice_ic = glob.glob(os.path.join(bkg_dir, f'{RUN}.*.agg_icef003.nc'))[0]
ufsda.disk_utils.symlink(cice_ic, os.path.join(anl_dir, 'INPUT', 'cice.res.nc'))
# Copy initial condition
ics_list = []
# ocean IC's
mom_ic_src = glob.glob(os.path.join(bkg_dir, f'{RUN}.*.ocnf003.nc'))[0]
mom_ic_dst = os.path.join(anl_dir, 'INPUT', 'MOM.res.nc')
ics_list.append([mom_ic_src, mom_ic_dst])

# seaice IC's
cice_ic_src = glob.glob(os.path.join(bkg_dir, f'{RUN}.*.agg_icef003.nc'))[0]
cice_ic_dst = os.path.join(anl_dir, 'INPUT', 'cice.res.nc')
ics_list.append([cice_ic_src, cice_ic_dst])
FileHandler({'copy': ics_list}).sync()

################################################################################
# prepare input.nml
mom_input_nml_src = os.path.join(gdas_home, 'parm', 'soca', 'fms', 'input.nml')
mom_input_nml_tmpl = os.path.join(stage_cfg['stage_dir'], 'mom_input.nml.tmpl')
mom_input_nml = os.path.join(stage_cfg['stage_dir'], 'mom_input.nml')
ufsda.disk_utils.copyfile(mom_input_nml_src, mom_input_nml_tmpl)
domain_stack_size = os.getenv('DOMAIN_STACK_SIZE')
FileHandler({'copy': [[mom_input_nml_src, mom_input_nml_tmpl]]}).sync()

# swap date and stack size
domain_stack_size = os.getenv('DOMAIN_STACK_SIZE')
ymdhms = [int(s) for s in window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')]
with open(mom_input_nml_tmpl, 'r') as nml_file:
nml = f90nml.read(nml_file)
Expand Down
Loading

0 comments on commit 0949755

Please sign in to comment.