From bc0f7d3bbccb9bd5c000d11b9c234798cba626d1 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 2 May 2024 18:18:42 +0000 Subject: [PATCH 01/50] inital commit of ocn letkf --- env/HERA.env | 8 +++++ env/ORION.env | 8 +++++ jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 47 ++++++++++++++++++++++++++ jobs/rocoto/ocnanalletkf.sh | 23 +++++++++++++ parm/config/gfs/config.ocnanalletkf | 11 ++++++ parm/config/gfs/config.resources | 31 ++++++++++++++++- sorc/link_workflow.sh | 1 + 7 files changed, 128 insertions(+), 1 deletion(-) create mode 100755 jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF create mode 100755 jobs/rocoto/ocnanalletkf.sh create mode 100644 parm/config/gfs/config.ocnanalletkf diff --git a/env/HERA.env b/env/HERA.env index 6ce99f8e90..b010293e8f 100755 --- a/env/HERA.env +++ b/env/HERA.env @@ -126,6 +126,14 @@ elif [[ "${step}" = "ocnanalecen" ]]; then [[ ${NTHREADS_OCNANALECEN} -gt ${nth_max} ]] && export NTHREADS_OCNANALECEN=${nth_max} export APRUN_OCNANALECEN="${launcher} -n ${npe_ocnanalecen} --cpus-per-task=${NTHREADS_OCNANALECEN}" +elif [[ "${step}" = "ocnanalletkf" ]]; then + + nth_max=$((npe_node_max / npe_node_ocnanalletkf)) + + export NTHREADS_OCNANALLETKF=${nth_ocnanalletkf:-${nth_max}} + [[ ${NTHREADS_OCNANALLETKF} -gt ${nth_max} ]] && export NTHREADS_OCNANALLETKF=${nth_max} + export APRUN_OCNANALLETKF="${launcher} -n ${npe_ocnanalletkf} --cpus-per-task=${NTHREADS_OCNANALLETKF}" + elif [[ "${step}" = "anal" ]] || [[ "${step}" = "analcalc" ]]; then export MKL_NUM_THREADS=4 diff --git a/env/ORION.env b/env/ORION.env index 6aac84a169..24cb17bb0d 100755 --- a/env/ORION.env +++ b/env/ORION.env @@ -134,6 +134,14 @@ elif [[ "${step}" = "ocnanalecen" ]]; then [[ ${NTHREADS_OCNANALECEN} -gt ${nth_max} ]] && export NTHREADS_OCNANALECEN=${nth_max} export APRUN_OCNANALECEN="${launcher} -n ${npe_ocnanalecen} --cpus-per-task=${NTHREADS_OCNANALECEN}" +elif [[ "${step}" = "ocnanalletkf" ]]; then + + nth_max=$((npe_node_max / npe_node_ocnanalletkf)) + + export NTHREADS_OCNANALLETKF=${nth_ocnanalletkf:-${nth_max}} + [[ ${NTHREADS_OCNANALLETKF} -gt ${nth_max} ]] && export NTHREADS_OCNANALLETKF=${nth_max} + export APRUN_OCNANALLETKF="${launcher} -n ${npe_ocnanalletkf} --cpus-per-task=${NTHREADS_OCNANALLETKF}" + elif [[ "${step}" = "anal" ]] || [[ "${step}" = "analcalc" ]]; then export MKL_NUM_THREADS=4 diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF new file mode 100755 index 0000000000..0223e98528 --- /dev/null +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -0,0 +1,47 @@ +#!/bin/bash +source "${HOMEgfs}/ush/preamble.sh" +source "${HOMEgfs}/ush/jjob_header.sh" -e "ocnanalletkf" -c "base ocnanal ocnanalletkf" + +############################################## +# Set variables used in the script +############################################## +# Ignore possible spelling error (nothing is misspelled) +# shellcheck disable=SC2153 +GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") +export gPDY=${GDATE:0:8} +export gcyc=${GDATE:8:2} + +YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ + COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ + COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL + +############################################## +# Begin JOB SPECIFIC work +############################################## + +############################################################### +# Run relevant script + +EXSCRIPT=${GDASOCNCENPY:-${HOMEgfs}/scripts/exgdas_global_marine_analysis_letkf.py} +${EXSCRIPT} +status=$? +[[ ${status} -ne 0 ]] && exit "${status}" + +############################################## +# End JOB SPECIFIC work +############################################## + +############################################## +# Final processing +############################################## +if [[ -e "${pgmout}" ]] ; then + cat "${pgmout}" +fi + +########################################## +# Remove the Temporary working directory +########################################## +cd "${DATAROOT}" || exit 1 +[[ "${KEEPDATA}" = "NO" ]] && rm -rf "${DATA}" + +exit 0 diff --git a/jobs/rocoto/ocnanalletkf.sh b/jobs/rocoto/ocnanalletkf.sh new file mode 100755 index 0000000000..cbea8113ee --- /dev/null +++ b/jobs/rocoto/ocnanalletkf.sh @@ -0,0 +1,23 @@ +#! /usr/bin/env bash + +source "${HOMEgfs}/ush/preamble.sh" + +############################################################### +# Source UFSDA workflow modules +. "${HOMEgfs}/ush/load_ufsda_modules.sh" +status=$? +[[ ${status} -ne 0 ]] && exit "${status}" + +export job="ocnanalletkf" +export jobid="${job}.$$" + +############################################################### +# Setup Python path for GDASApp ush +PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}${HOMEgfs}/sorc/gdas.cd/ush" +export PYTHONPATH + +############################################################### +# Execute the JJOB +"${HOMEgfs}"/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +status=$? +exit "${status}" diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.ocnanalletkf new file mode 100644 index 0000000000..b67f37152e --- /dev/null +++ b/parm/config/gfs/config.ocnanalletkf @@ -0,0 +1,11 @@ +#!/bin/bash + +########## config.ocnanalletkf ########## +# Ocn Analysis specific + +echo "BEGIN: config.ocnanalletkf" + +# Get task specific resources +. "${EXPDIR}/config.resources" ocnanalletkf + +echo "END: config.ocnanalletkf" diff --git a/parm/config/gfs/config.resources b/parm/config/gfs/config.resources index aafe7b0967..d92f905b7b 100644 --- a/parm/config/gfs/config.resources +++ b/parm/config/gfs/config.resources @@ -23,7 +23,7 @@ if (( $# != 1 )); then echo "waveinit waveprep wavepostsbs wavepostbndpnt wavepostbndpntbll wavepostpnt" echo "wavegempak waveawipsbulls waveawipsgridded" echo "postsnd awips gempak npoess" - echo "ocnanalprep prepoceanobs ocnanalbmat ocnanalrun ocnanalecen ocnanalchkpt ocnanalpost ocnanalvrfy" + echo "ocnanalprep prepoceanobs ocnanalbmat ocnanalrun ocnanalecen ocnanalletkf ocnanalchkpt ocnanalpost ocnanalvrfy" exit 1 fi @@ -442,6 +442,35 @@ case ${step} in export memory_ocnanalecen ;; + "ocnanalletkf") + npes=16 + case ${OCNRES} in + "025") + npes=40 + memory_ocnanalletkf="96GB" + ;; + "050") + npes=16 + memory_ocnanalletkf="96GB" + ;; + "500") + npes=16 + memory_ocnanalletkf="24GB" + ;; + *) + echo "FATAL ERROR: Resources not defined for job ${job} at resolution ${OCNRES}" + exit 4 + esac + + export wtime_ocnanalletkf="00:10:00" + export npe_ocnanalletkf=${npes} + export nth_ocnanalletkf=1 + export is_exclusive=True + export npe_node_ocnanalletkf=$(( npe_node_max / nth_ocnanalletkf )) + export memory_ocnanalletkf + ;; + + "ocnanalchkpt") export wtime_ocnanalchkpt="00:10:00" export npe_ocnanalchkpt=1 diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index 7106d1ed79..60b2a37894 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -163,6 +163,7 @@ ${LINK_OR_COPY} "${HOMEgfs}/sorc/ufs_utils.fd/scripts/exemcsfc_global_sfc_prep.s if [[ -d "${HOMEgfs}/sorc/gdas.cd" ]]; then declare -a gdas_scripts=(exglobal_prep_ocean_obs.py \ exgdas_global_marine_analysis_ecen.py \ + exgdas_global_marine_analysis_letkf.py \ ) for gdas_script in "${gdas_scripts[@]}" ; do ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/scripts/${gdas_script}" . From 4cbc978132e43d63114c22f5d4eae68bc69726b2 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 3 May 2024 15:36:33 +0000 Subject: [PATCH 02/50] change recsources --- parm/config/gfs/config.resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parm/config/gfs/config.resources b/parm/config/gfs/config.resources index d92f905b7b..67a91c71e5 100644 --- a/parm/config/gfs/config.resources +++ b/parm/config/gfs/config.resources @@ -446,7 +446,7 @@ case ${step} in npes=16 case ${OCNRES} in "025") - npes=40 + npes=480 memory_ocnanalletkf="96GB" ;; "050") From faee5e5cfcabcb973d332a80f3805bbde972733f Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Mon, 6 May 2024 15:25:48 +0000 Subject: [PATCH 03/50] tweaks --- .gitignore | 1 + jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 39d140fd65..2ae8ebc517 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ sorc/ocnicepost.fd # scripts symlinks scripts/exemcsfc_global_sfc_prep.sh scripts/exgdas_global_marine_analysis_ecen.py +scripts/exgdas_global_marine_analysis_letkf.py scripts/exglobal_prep_ocean_obs.py # ush symlinks ush/chgres_cube.sh diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index 0223e98528..21aa95c3c5 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -22,7 +22,7 @@ YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ ############################################################### # Run relevant script -EXSCRIPT=${GDASOCNCENPY:-${HOMEgfs}/scripts/exgdas_global_marine_analysis_letkf.py} +EXSCRIPT=${GDASOCNLETKFPY:-${HOMEgfs}/scripts/exgdas_global_marine_analysis_letkf.py} ${EXSCRIPT} status=$? [[ ${status} -ne 0 ]] && exit "${status}" From 6cbf20309dbe22b9fbee86e75e0d5971c4b1bdde Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 7 May 2024 13:17:00 -0500 Subject: [PATCH 04/50] move from gdasapp --- .gitignore | 1 - .../exgdas_global_marine_analysis_letkf.py | 25 +++++++++++++++++++ sorc/link_workflow.sh | 1 - 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100755 scripts/exgdas_global_marine_analysis_letkf.py diff --git a/.gitignore b/.gitignore index 2ae8ebc517..39d140fd65 100644 --- a/.gitignore +++ b/.gitignore @@ -159,7 +159,6 @@ sorc/ocnicepost.fd # scripts symlinks scripts/exemcsfc_global_sfc_prep.sh scripts/exgdas_global_marine_analysis_ecen.py -scripts/exgdas_global_marine_analysis_letkf.py scripts/exglobal_prep_ocean_obs.py # ush symlinks ush/chgres_cube.sh diff --git a/scripts/exgdas_global_marine_analysis_letkf.py b/scripts/exgdas_global_marine_analysis_letkf.py new file mode 100755 index 0000000000..107eeef1ff --- /dev/null +++ b/scripts/exgdas_global_marine_analysis_letkf.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# exgdas_global_marine_analysis_ecen.py +# This script creates an MarineLETKF class +# and runs the initialize, run, and finalize methods +# which currently are stubs +import os + +from wxflow import Logger, cast_strdict_as_dtypedict +# TODO (AFE): change to from pygfs.task.marine_recenter import MarineLETKF +from soca.marine_letkf import MarineLETKF + +# Initialize root logger +logger = Logger(level='DEBUG', colored_log=True) + + +if __name__ == '__main__': + + # Take configuration from environment and cast it as python dictionary + config = cast_strdict_as_dtypedict(os.environ) + + # Instantiate the aerosol analysis task + MarineLetkf = MarineLETKF(config) + MarineLetkf.initialize() + MarineLetkf.run() + MarineLetkf.finalize() diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index ac3520524a..0041ce083b 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -163,7 +163,6 @@ ${LINK_OR_COPY} "${HOMEgfs}/sorc/ufs_utils.fd/scripts/exemcsfc_global_sfc_prep.s if [[ -d "${HOMEgfs}/sorc/gdas.cd" ]]; then declare -a gdas_scripts=(exglobal_prep_ocean_obs.py \ exgdas_global_marine_analysis_ecen.py \ - exgdas_global_marine_analysis_letkf.py \ ) for gdas_script in "${gdas_scripts[@]}" ; do ${LINK_OR_COPY} "${HOMEgfs}/sorc/gdas.cd/scripts/${gdas_script}" . From 20312fbdd18a21396eef0fb41b413fce1668064a Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 7 May 2024 13:24:28 -0500 Subject: [PATCH 05/50] removing spurious refs to centering --- scripts/exgdas_global_marine_analysis_letkf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/exgdas_global_marine_analysis_letkf.py b/scripts/exgdas_global_marine_analysis_letkf.py index 107eeef1ff..bbf33cb812 100755 --- a/scripts/exgdas_global_marine_analysis_letkf.py +++ b/scripts/exgdas_global_marine_analysis_letkf.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 -# exgdas_global_marine_analysis_ecen.py +# exgdas_global_marine_analysis_letkf.py # This script creates an MarineLETKF class -# and runs the initialize, run, and finalize methods +# and runs the initialize, run, and finalize methods # which currently are stubs import os from wxflow import Logger, cast_strdict_as_dtypedict -# TODO (AFE): change to from pygfs.task.marine_recenter import MarineLETKF from soca.marine_letkf import MarineLETKF # Initialize root logger From 2f9ed0a79a2f7629a924d6b52289a7bd038e2376 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 7 May 2024 14:35:46 -0500 Subject: [PATCH 06/50] move from gdasapp --- .../exgdas_global_marine_analysis_letkf.py | 2 +- ush/python/pygfs/task/marine_letkf.py | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 ush/python/pygfs/task/marine_letkf.py diff --git a/scripts/exgdas_global_marine_analysis_letkf.py b/scripts/exgdas_global_marine_analysis_letkf.py index bbf33cb812..f2edf487c8 100755 --- a/scripts/exgdas_global_marine_analysis_letkf.py +++ b/scripts/exgdas_global_marine_analysis_letkf.py @@ -6,7 +6,7 @@ import os from wxflow import Logger, cast_strdict_as_dtypedict -from soca.marine_letkf import MarineLETKF +from pygfs.task.marine_letkf import MarineLETKF # Initialize root logger logger = Logger(level='DEBUG', colored_log=True) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py new file mode 100644 index 0000000000..e5b75ae97e --- /dev/null +++ b/ush/python/pygfs/task/marine_letkf.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +from datetime import datetime, timedelta +import f90nml +from logging import getLogger +import os +from soca import bkg_utils +from typing import Dict +import ufsda +from ufsda.stage import soca_fix +from wxflow import (AttrDict, + chdir, + Executable, + FileHandler, + logit, + parse_j2yaml, + Task, + Template, + TemplateConstants, + WorkflowException, + YAMLFile) + +logger = getLogger(__name__.split('.')[-1]) + + +class MarineLETKF(Task): + """ + Class for global ocean analysis LETKF task + """ + + @logit(logger, name="MarineLETKF") + def __init__(self, config: Dict) -> None: + """Constructor for ocean LETKF task + Parameters: + ------------ + config: Dict + configuration, namely evironment variables + Returns: + -------- + None + """ + + logger.info("init") + super().__init__(config) + + @logit(logger) + def initialize(self): + """Method initialize for ocean LETKF task + Parameters: + ------------ + None + Returns: + -------- + None + """ + + logger.info("initialize") + RUN = self.runtime_config.RUN + + @logit(logger) + def run(self): + """Method run for ocean LETKF task + Parameters: + ------------ + None + Returns: + -------- + None + """ + + logger.info("run") + + chdir(self.runtime_config.DATA) + + @logit(logger) + def finalize(self): + """Method finalize for ocean LETKF task + Parameters: + ------------ + None + Returns: + -------- + None + """ + + logger.info("finalize") + + RUN = self.runtime_config.RUN + cyc = self.runtime_config.cyc From 19a6901e44193dc56e9d9705ad6fded34cb6f1dc Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 9 May 2024 13:45:21 +0000 Subject: [PATCH 07/50] review tweaks --- ush/python/pygfs/task/marine_letkf.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index e5b75ae97e..cd95bb4bc8 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -1,24 +1,10 @@ #!/usr/bin/env python3 -from datetime import datetime, timedelta -import f90nml from logging import getLogger -import os -from soca import bkg_utils from typing import Dict -import ufsda -from ufsda.stage import soca_fix -from wxflow import (AttrDict, - chdir, - Executable, - FileHandler, +from wxflow import (chdir, logit, - parse_j2yaml, - Task, - Template, - TemplateConstants, - WorkflowException, - YAMLFile) + Task) logger = getLogger(__name__.split('.')[-1]) @@ -55,7 +41,6 @@ def initialize(self): """ logger.info("initialize") - RUN = self.runtime_config.RUN @logit(logger) def run(self): @@ -85,5 +70,3 @@ def finalize(self): logger.info("finalize") - RUN = self.runtime_config.RUN - cyc = self.runtime_config.cyc From f5b4ba9eaae6fc33751f04883660fcb165c97715 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA <58948505+AndrewEichmann-NOAA@users.noreply.github.com> Date: Thu, 9 May 2024 09:46:50 -0400 Subject: [PATCH 08/50] Update jobs/rocoto/ocnanalletkf.sh Co-authored-by: Rahul Mahajan --- jobs/rocoto/ocnanalletkf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jobs/rocoto/ocnanalletkf.sh b/jobs/rocoto/ocnanalletkf.sh index cbea8113ee..12230d780c 100755 --- a/jobs/rocoto/ocnanalletkf.sh +++ b/jobs/rocoto/ocnanalletkf.sh @@ -13,7 +13,7 @@ export jobid="${job}.$$" ############################################################### # Setup Python path for GDASApp ush -PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}${HOMEgfs}/sorc/gdas.cd/ush" +PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}${HOMEgfs}/ush/python" export PYTHONPATH ############################################################### From 6d131370af90b2a0d17c936090be19cf7ac67574 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA <58948505+AndrewEichmann-NOAA@users.noreply.github.com> Date: Thu, 9 May 2024 09:47:03 -0400 Subject: [PATCH 09/50] Update jobs/rocoto/ocnanalletkf.sh Co-authored-by: Rahul Mahajan --- jobs/rocoto/ocnanalletkf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jobs/rocoto/ocnanalletkf.sh b/jobs/rocoto/ocnanalletkf.sh index 12230d780c..f710be5710 100755 --- a/jobs/rocoto/ocnanalletkf.sh +++ b/jobs/rocoto/ocnanalletkf.sh @@ -18,6 +18,6 @@ export PYTHONPATH ############################################################### # Execute the JJOB -"${HOMEgfs}"/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +"${HOMEgfs}/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF" status=$? exit "${status}" From 7c5083b297249b169f0d7d3f3d92388b0ab8d92d Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA <58948505+AndrewEichmann-NOAA@users.noreply.github.com> Date: Thu, 9 May 2024 09:47:18 -0400 Subject: [PATCH 10/50] Update jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF Co-authored-by: Rahul Mahajan --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 2 -- 1 file changed, 2 deletions(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index 21aa95c3c5..cb73ddbfc6 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -8,8 +8,6 @@ source "${HOMEgfs}/ush/jjob_header.sh" -e "ocnanalletkf" -c "base ocnanal ocnana # Ignore possible spelling error (nothing is misspelled) # shellcheck disable=SC2153 GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") -export gPDY=${GDATE:0:8} -export gcyc=${GDATE:8:2} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ From 6551a5b6d3b597994d7b13f340d01dc8f3ff60fd Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 9 May 2024 17:55:38 +0000 Subject: [PATCH 11/50] tweaks --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 3 +++ ush/python/pygfs/task/marine_letkf.py | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index cb73ddbfc6..d03ddfc19a 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -9,6 +9,9 @@ source "${HOMEgfs}/ush/jjob_header.sh" -e "ocnanalletkf" -c "base ocnanal ocnana # shellcheck disable=SC2153 GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") +gPDY=${GDATE:0:8} +gcyc=${GDATE:8:2} + YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index cd95bb4bc8..9823f7743d 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -69,4 +69,3 @@ def finalize(self): """ logger.info("finalize") - From ade109a61d40a48ac0cfea91002fae89946281d3 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 9 May 2024 18:47:59 +0000 Subject: [PATCH 12/50] swap in analysis class --- ush/python/pygfs/task/marine_letkf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 9823f7743d..a42331770e 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from logging import getLogger +from pygfs.task.analysis import Analysis from typing import Dict from wxflow import (chdir, logit, @@ -9,7 +10,7 @@ logger = getLogger(__name__.split('.')[-1]) -class MarineLETKF(Task): +class MarineLETKF(Analysis): """ Class for global ocean analysis LETKF task """ From 5fb0a68cf59e100e8d46db5afbd01f361d35a6ce Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 10 May 2024 18:37:43 +0000 Subject: [PATCH 13/50] comment changes --- ush/python/pygfs/task/marine_letkf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index a42331770e..0ae5bea98d 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -12,12 +12,12 @@ class MarineLETKF(Analysis): """ - Class for global ocean analysis LETKF task + Class for global ocean and sea ice analysis LETKF task """ @logit(logger, name="MarineLETKF") def __init__(self, config: Dict) -> None: - """Constructor for ocean LETKF task + """Constructor for ocean and sea ice LETKF task Parameters: ------------ config: Dict @@ -32,7 +32,7 @@ def __init__(self, config: Dict) -> None: @logit(logger) def initialize(self): - """Method initialize for ocean LETKF task + """Method initialize for ocean and sea ice LETKF task Parameters: ------------ None @@ -45,7 +45,7 @@ def initialize(self): @logit(logger) def run(self): - """Method run for ocean LETKF task + """Method run for ocean and sea ice LETKF task Parameters: ------------ None @@ -60,7 +60,7 @@ def run(self): @logit(logger) def finalize(self): - """Method finalize for ocean LETKF task + """Method finalize for ocean and sea ice LETKF task Parameters: ------------ None From 00a14d9a0e4464b2f9bb1c48f5d2a6473d046524 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Mon, 13 May 2024 21:36:21 +0000 Subject: [PATCH 14/50] copy bkg --- parm/config/gfs/config.ocnanalletkf | 2 ++ ush/python/pygfs/task/marine_letkf.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.ocnanalletkf index b67f37152e..239dc7d453 100644 --- a/parm/config/gfs/config.ocnanalletkf +++ b/parm/config/gfs/config.ocnanalletkf @@ -8,4 +8,6 @@ echo "BEGIN: config.ocnanalletkf" # Get task specific resources . "${EXPDIR}/config.resources" ocnanalletkf +KEEPDATA="YES" + echo "END: config.ocnanalletkf" diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 0ae5bea98d..8ffff5af5c 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -1,9 +1,13 @@ #!/usr/bin/env python3 +from datetime import timedelta from logging import getLogger +from os import path from pygfs.task.analysis import Analysis +from soca import bkg_utils from typing import Dict from wxflow import (chdir, + FileHandler, logit, Task) @@ -30,6 +34,18 @@ def __init__(self, config: Dict) -> None: logger.info("init") super().__init__(config) + PDY = self.runtime_config['PDY'] + cyc = self.runtime_config['cyc'] + DATA = self.runtime_config.DATA + cdate = PDY + timedelta(hours=cyc) + + half_assim_freq = timedelta(hours=int(config['assim_freq'])/2) + window_begin = cdate - half_assim_freq + + self.config['window_begin'] = window_begin + self.config['BKG_LIST'] = 'bkg_list.yaml' + self.config['bkg_dir'] = path.join(DATA, 'bkg') + @logit(logger) def initialize(self): """Method initialize for ocean and sea ice LETKF task @@ -43,6 +59,13 @@ def initialize(self): logger.info("initialize") + + FileHandler({'mkdir': [self.config.bkg_dir]}).sync() + bkg_utils.gen_bkg_list(bkg_path=self.config.COM_OCEAN_HISTORY_PREV, + out_path=self.config.bkg_dir, + window_begin=self.config.window_begin, + yaml_name=self.config.BKG_LIST) + @logit(logger) def run(self): """Method run for ocean and sea ice LETKF task From 0d10340f1257d89d9b6282047f768cc69adf470f Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 15 May 2024 13:57:42 +0000 Subject: [PATCH 15/50] towards complete task --- ush/python/pygfs/task/marine_letkf.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 8ffff5af5c..441fb694d8 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -39,13 +39,25 @@ def __init__(self, config: Dict) -> None: DATA = self.runtime_config.DATA cdate = PDY + timedelta(hours=cyc) + gdas_home = path.join(config['HOMEgfs'], 'sorc', 'gdas.cd') + half_assim_freq = timedelta(hours=int(config['assim_freq'])/2) window_begin = cdate - half_assim_freq + letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') + + self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') + self.config['letkf_yaml_file'] = path.join(DATA, 'letkf.yaml') self.config['window_begin'] = window_begin self.config['BKG_LIST'] = 'bkg_list.yaml' self.config['bkg_dir'] = path.join(DATA, 'bkg') + exec_name_gridgen = path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') + self.config['gridgen_yaml'] = path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml') + + + + @logit(logger) def initialize(self): """Method initialize for ocean and sea ice LETKF task @@ -81,6 +93,10 @@ def run(self): chdir(self.runtime_config.DATA) + exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) + exec_cmd_gridgen.add_default_arg(exec_name_gridgen) + exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) + @logit(logger) def finalize(self): """Method finalize for ocean and sea ice LETKF task From 60486d1d6a8a0305736686e9ced7bc263ae6a2e7 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 16 May 2024 19:21:19 +0000 Subject: [PATCH 16/50] does gridgen --- .../exgdas_global_marine_analysis_letkf.py | 2 +- ush/python/pygfs/task/marine_letkf.py | 65 +++++++++++++++++-- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/scripts/exgdas_global_marine_analysis_letkf.py b/scripts/exgdas_global_marine_analysis_letkf.py index f2edf487c8..37ca837889 100755 --- a/scripts/exgdas_global_marine_analysis_letkf.py +++ b/scripts/exgdas_global_marine_analysis_letkf.py @@ -17,7 +17,7 @@ # Take configuration from environment and cast it as python dictionary config = cast_strdict_as_dtypedict(os.environ) - # Instantiate the aerosol analysis task + # Instantiate the marine letkf task MarineLetkf = MarineLETKF(config) MarineLetkf.initialize() MarineLetkf.run() diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 441fb694d8..ecd1aa9398 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -1,15 +1,21 @@ #!/usr/bin/env python3 from datetime import timedelta +import f90nml from logging import getLogger from os import path from pygfs.task.analysis import Analysis from soca import bkg_utils from typing import Dict -from wxflow import (chdir, +import ufsda +from ufsda.stage import soca_fix +from wxflow import (AttrDict, + chdir, + Executable, FileHandler, logit, - Task) + Task, + WorkflowException) logger = getLogger(__name__.split('.')[-1]) @@ -43,7 +49,24 @@ def __init__(self, config: Dict) -> None: half_assim_freq = timedelta(hours=int(config['assim_freq'])/2) window_begin = cdate - half_assim_freq + window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') + window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') + gdate = cdate - timedelta(hours=6) + self.runtime_config['gcyc'] = gdate.strftime("%H") + + self.stage_config = AttrDict( + {'window_begin': f"{window_begin.strftime('%Y-%m-%dT%H:%M:%SZ')}", + 'ATM_WINDOW_BEGIN': window_begin_iso, + 'ATM_WINDOW_MIDDLE': window_middle_iso, + 'DATA': DATA, + 'dump': self.runtime_config.RUN, + 'fv3jedi_stage_files': self.config.FV3JEDI_STAGE_YAML, + 'fv3jedi_stage': self.config.FV3JEDI_STAGE_YAML, + 'stage_dir': DATA, + 'soca_input_fix_dir': self.config.SOCA_INPUT_FIX_DIR, + 'NMEM_ENS': self.config.NMEM_ENS, + 'ATM_WINDOW_LENGTH': f"PT{config['assim_freq']}H"}) self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') self.config['letkf_yaml_file'] = path.join(DATA, 'letkf.yaml') @@ -52,12 +75,17 @@ def __init__(self, config: Dict) -> None: self.config['BKG_LIST'] = 'bkg_list.yaml' self.config['bkg_dir'] = path.join(DATA, 'bkg') - exec_name_gridgen = path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') + self.config.exec_name_gridgen = path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') self.config['gridgen_yaml'] = path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml') + self.config.mom_input_nml_src = path.join(gdas_home, 'parm', 'soca', 'fms', 'input.nml') + self.config.mom_input_nml_tmpl = path.join(DATA, 'mom_input.nml.tmpl') + self.config.mom_input_nml = path.join(DATA, 'mom_input.nml') + + @logit(logger) def initialize(self): """Method initialize for ocean and sea ice LETKF task @@ -93,10 +121,39 @@ def run(self): chdir(self.runtime_config.DATA) + FileHandler({'copy': [[self.config.mom_input_nml_src, + self.config.mom_input_nml_tmpl]]}).sync() + + ufsda.stage.soca_fix(self.stage_config) + + bkg_utils.stage_ic(self.config.bkg_dir, self.runtime_config.DATA, self.runtime_config.gcyc) + + # swap date and stack size + #domain_stack_size = os.getenv('DOMAIN_STACK_SIZE') + domain_stack_size = self.config.DOMAIN_STACK_SIZE + ymdhms = [int(s) for s in self.config.window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')] + with open(self.config.mom_input_nml_tmpl, 'r') as nml_file: + nml = f90nml.read(nml_file) + nml['ocean_solo_nml']['date_init'] = ymdhms + nml['fms_nml']['domains_stack_size'] = int(domain_stack_size) + ufsda.disk_utils.removefile(self.config.mom_input_nml) + nml.write(self.config.mom_input_nml) + + exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) - exec_cmd_gridgen.add_default_arg(exec_name_gridgen) + exec_cmd_gridgen.add_default_arg(self.config.exec_name_gridgen) exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) + try: + logger.debug(f"Executing {exec_cmd_gridgen}") + exec_cmd_gridgen() + except OSError: + raise OSError(f"Failed to execute {exec_cmd_gridgen}") + except Exception: + raise WorkflowException(f"An error occured during execution of {exec_cmd_gridgen}") + pass + + @logit(logger) def finalize(self): """Method finalize for ocean and sea ice LETKF task From 8d378f704233f40b3c5465bf3fbf4b99149f9e7b Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Mon, 20 May 2024 21:57:03 +0000 Subject: [PATCH 17/50] does the gridgen --- ush/python/pygfs/task/marine_letkf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index ecd1aa9398..6095278fc4 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -82,6 +82,8 @@ def __init__(self, config: Dict) -> None: self.config.mom_input_nml_tmpl = path.join(DATA, 'mom_input.nml.tmpl') self.config.mom_input_nml = path.join(DATA, 'mom_input.nml') + self.config.data_output = 'data_output' + self.config.ensdir = 'ens' @@ -101,6 +103,9 @@ def initialize(self): FileHandler({'mkdir': [self.config.bkg_dir]}).sync() + FileHandler({'mkdir': [self.config.data_output]}).sync() + FileHandler({'mkdir': [self.config.ens_dir]}).sync() + bkg_utils.gen_bkg_list(bkg_path=self.config.COM_OCEAN_HISTORY_PREV, out_path=self.config.bkg_dir, window_begin=self.config.window_begin, From 5e86d40470586fe720f0ae334c0a72f81775ab5a Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 22 May 2024 14:28:40 +0000 Subject: [PATCH 18/50] latest --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 2 + ush/python/pygfs/task/marine_letkf.py | 51 ++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index d03ddfc19a..e53a62e017 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -16,6 +16,8 @@ YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL +YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COM_OBS + ############################################## # Begin JOB SPECIFIC work ############################################## diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 6095278fc4..1cefd247b5 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -14,8 +14,10 @@ Executable, FileHandler, logit, + parse_j2yaml, Task, - WorkflowException) + WorkflowException, + YAMLFile) logger = getLogger(__name__.split('.')[-1]) @@ -83,10 +85,10 @@ def __init__(self, config: Dict) -> None: self.config.mom_input_nml = path.join(DATA, 'mom_input.nml') self.config.data_output = 'data_output' - self.config.ensdir = 'ens' - - + self.config.ens_dir = 'ens' + self.config.ATM_WINDOW_BEGIN = window_begin_iso + self.config.ATM_WINDOW_MIDDLE = window_middle_iso @logit(logger) def initialize(self): @@ -102,15 +104,56 @@ def initialize(self): logger.info("initialize") + PDYstr = self.runtime_config.PDY.strftime("%Y%m%d") + FileHandler({'mkdir': [self.config.bkg_dir]}).sync() FileHandler({'mkdir': [self.config.data_output]}).sync() FileHandler({'mkdir': [self.config.ens_dir]}).sync() + + chdir(self.config.ens_dir) + for mem in range(1,self.config.NMEM_ENS+1): + #mem_dir = path.realpath(path.join(self.config.ens_dir , f'mem{str(mem).zfill(3)}')) + #mem_dir = path.realpath(path.join('fdsfsds' , f'mem{str(mem).zfill(3)}')) + mem_dir = f'mem{str(mem).zfill(3)}' + print('mem_dir: ',mem_dir) + FileHandler({'mkdir': [mem_dir]}).sync() + chdir(self.runtime_config.DATA) bkg_utils.gen_bkg_list(bkg_path=self.config.COM_OCEAN_HISTORY_PREV, out_path=self.config.bkg_dir, window_begin=self.config.window_begin, yaml_name=self.config.BKG_LIST) + obs_list = YAMLFile(self.config.OBS_YAML) + + # get the list of observations + obs_files = [] + for ob in obs_list['observers']: + obs_name = ob['obs space']['name'].lower() + obs_filename = f"{self.runtime_config.RUN}.t{self.runtime_config.cyc}z.{ob['obs space']['name'].lower()}.{PDYstr}{self.runtime_config.cyc}.nc4" + obs_files.append((obs_filename,ob)) + obs_list = [] + + obs_to_use = [] + # copy obs from COM_OBS to DATA/obs + for obs_file, ob in obs_files: + logger.info(f"******* {obs_file}") + obs_src = path.join(self.config.COM_OBS, obs_file) + obs_dst = path.join(self.runtime_config.DATA, obs_file) + logger.info(f"******* {obs_src}") + if path.exists(obs_src): + logger.info(f"******* fetching {obs_file}") + obs_list.append([obs_src, obs_dst]) + obs_to_use.append(ob) + else: + logger.info(f"******* {obs_file} is not in the database") + + FileHandler({'copy': obs_list}).sync() + + letkf_yaml = parse_j2yaml(self.config.letkf_yaml_template, self.config) + letkf_yaml.observations.observers = obs_to_use + letkf_yaml.save(self.config.letkf_yaml_file) + @logit(logger) def run(self): """Method run for ocean and sea ice LETKF task From 27f4eb99b08b81d593585da4d8997ffbce635749 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 23 May 2024 00:02:28 +0000 Subject: [PATCH 19/50] now copies ensemble --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 5 ++- ush/python/pygfs/task/marine_letkf.py | 62 +++++++++++++++++++++----- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index e53a62e017..d21537e4cd 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -9,14 +9,15 @@ source "${HOMEgfs}/ush/jjob_header.sh" -e "ocnanalletkf" -c "base ocnanal ocnana # shellcheck disable=SC2153 GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") -gPDY=${GDATE:0:8} +export gPDY=${GDATE:0:8} gcyc=${GDATE:8:2} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL -YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COM_OBS +YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COM_OBS +ROTDIR=${COMROOT} RUN=enkf${RUN} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COM_TOP_PREV_ENS:COM_TOP_TMPL ############################################## # Begin JOB SPECIFIC work diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 1cefd247b5..2de8cf93bd 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -44,8 +44,12 @@ def __init__(self, config: Dict) -> None: PDY = self.runtime_config['PDY'] cyc = self.runtime_config['cyc'] + gcyc = str(self.config['gcyc']).zfill(2) + gPDY = self.config['gPDY'] + RUN = self.runtime_config.RUN DATA = self.runtime_config.DATA cdate = PDY + timedelta(hours=cyc) + COM_TOP_PREV_ENS = self.config.COM_TOP_PREV_ENS gdas_home = path.join(config['HOMEgfs'], 'sorc', 'gdas.cd') @@ -89,6 +93,46 @@ def __init__(self, config: Dict) -> None: self.config.ATM_WINDOW_BEGIN = window_begin_iso self.config.ATM_WINDOW_MIDDLE = window_middle_iso + + # set up lists of files for ens background + self.config.ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{gcyc}z.inst.f009.nc" + self.config.ice_ens_bkg_filename = f"enkf{RUN}.ice.t{gcyc}z.inst.f009.nc" + + # create list of subdirs to make in initialize, and list of some of the files to stage + ens_bkg_files_to_stage = [] + ens_mem_dirs = [self.config.bkg_dir, self.config.data_output] + for mem in range(1,self.config.NMEM_ENS+1): + mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 + ens_mem_dirs.append(path.join(self.config.ens_dir,mem_dir)) + print(":COM_TOP_PREV_ENS ",COM_TOP_PREV_ENS) + print("mem_dir: ",mem_dir) + print("self.config.ocn_ens_bkg_filename: ",self.config.ocn_ens_bkg_filename) + ocn_file_path = path.join(COM_TOP_PREV_ENS, + mem_dir, + 'model_data', + 'ocean', + 'history', + self.config.ocn_ens_bkg_filename) + ocn_file_dest = path.join(self.config.ens_dir, + mem_dir, + self.config.ocn_ens_bkg_filename) + ice_file_path = path.join(COM_TOP_PREV_ENS, + mem_dir, + 'model_data', + 'ice', + 'history', + self.config.ice_ens_bkg_filename) + ice_file_dest = path.join(self.config.ens_dir, + mem_dir, + self.config.ice_ens_bkg_filename) + ens_bkg_files_to_stage.append((ocn_file_path, ocn_file_dest)) + ens_bkg_files_to_stage.append((ice_file_path, ice_file_dest)) + + self.config.ens_bkg_files_to_stage = ens_bkg_files_to_stage + self.config.ens_mem_dirs = ens_mem_dirs + + + @logit(logger) def initialize(self): @@ -105,20 +149,14 @@ def initialize(self): PDYstr = self.runtime_config.PDY.strftime("%Y%m%d") + ens_dir = self.config.ens_dir + RUN = self.runtime_config.RUN - FileHandler({'mkdir': [self.config.bkg_dir]}).sync() - FileHandler({'mkdir': [self.config.data_output]}).sync() - FileHandler({'mkdir': [self.config.ens_dir]}).sync() - + # create directories under DATA + FileHandler({'mkdir': self.config.ens_mem_dirs }).sync() + # copy ensemble background to DATA/ens/mem??? + FileHandler({'copy': self.config.ens_bkg_files_to_stage }).sync() - chdir(self.config.ens_dir) - for mem in range(1,self.config.NMEM_ENS+1): - #mem_dir = path.realpath(path.join(self.config.ens_dir , f'mem{str(mem).zfill(3)}')) - #mem_dir = path.realpath(path.join('fdsfsds' , f'mem{str(mem).zfill(3)}')) - mem_dir = f'mem{str(mem).zfill(3)}' - print('mem_dir: ',mem_dir) - FileHandler({'mkdir': [mem_dir]}).sync() - chdir(self.runtime_config.DATA) bkg_utils.gen_bkg_list(bkg_path=self.config.COM_OCEAN_HISTORY_PREV, out_path=self.config.bkg_dir, window_begin=self.config.window_begin, From 90d0519458e2669721a3f83c0c2b35e3f42520b6 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 23 May 2024 15:28:55 +0000 Subject: [PATCH 20/50] cleanup and rationalisation --- ush/python/pygfs/task/marine_letkf.py | 40 +++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 2de8cf93bd..4971f52cec 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -95,41 +95,38 @@ def __init__(self, config: Dict) -> None: self.config.ATM_WINDOW_MIDDLE = window_middle_iso # set up lists of files for ens background - self.config.ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{gcyc}z.inst.f009.nc" - self.config.ice_ens_bkg_filename = f"enkf{RUN}.ice.t{gcyc}z.inst.f009.nc" + ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{gcyc}z.inst.f009.nc" + ice_ens_bkg_filename = f"enkf{RUN}.ice.t{gcyc}z.inst.f009.nc" # create list of subdirs to make in initialize, and list of some of the files to stage ens_bkg_files_to_stage = [] - ens_mem_dirs = [self.config.bkg_dir, self.config.data_output] + dirs_to_make = [self.config.bkg_dir, self.config.data_output] for mem in range(1,self.config.NMEM_ENS+1): mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 - ens_mem_dirs.append(path.join(self.config.ens_dir,mem_dir)) - print(":COM_TOP_PREV_ENS ",COM_TOP_PREV_ENS) - print("mem_dir: ",mem_dir) - print("self.config.ocn_ens_bkg_filename: ",self.config.ocn_ens_bkg_filename) + dirs_to_make.append(path.join(self.config.ens_dir,mem_dir)) ocn_file_path = path.join(COM_TOP_PREV_ENS, mem_dir, 'model_data', 'ocean', 'history', - self.config.ocn_ens_bkg_filename) + ocn_ens_bkg_filename) ocn_file_dest = path.join(self.config.ens_dir, mem_dir, - self.config.ocn_ens_bkg_filename) + ocn_ens_bkg_filename) ice_file_path = path.join(COM_TOP_PREV_ENS, mem_dir, 'model_data', 'ice', 'history', - self.config.ice_ens_bkg_filename) + ice_ens_bkg_filename) ice_file_dest = path.join(self.config.ens_dir, mem_dir, - self.config.ice_ens_bkg_filename) + ice_ens_bkg_filename) ens_bkg_files_to_stage.append((ocn_file_path, ocn_file_dest)) ens_bkg_files_to_stage.append((ice_file_path, ice_file_dest)) self.config.ens_bkg_files_to_stage = ens_bkg_files_to_stage - self.config.ens_mem_dirs = ens_mem_dirs + self.config.dirs_to_make = dirs_to_make @@ -147,13 +144,15 @@ def initialize(self): logger.info("initialize") - - PDYstr = self.runtime_config.PDY.strftime("%Y%m%d") + cyc = self.runtime_config.cyc + DATA = self.runtime_config.DATA ens_dir = self.config.ens_dir + PDYstr = self.runtime_config.PDY.strftime("%Y%m%d") RUN = self.runtime_config.RUN # create directories under DATA - FileHandler({'mkdir': self.config.ens_mem_dirs }).sync() + FileHandler({'mkdir': self.config.dirs_to_make}).sync() + # copy ensemble background to DATA/ens/mem??? FileHandler({'copy': self.config.ens_bkg_files_to_stage }).sync() @@ -168,26 +167,27 @@ def initialize(self): obs_files = [] for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() - obs_filename = f"{self.runtime_config.RUN}.t{self.runtime_config.cyc}z.{ob['obs space']['name'].lower()}.{PDYstr}{self.runtime_config.cyc}.nc4" + obs_filename = f"{RUN}.t{cyc}z.{obs_name}.{PDYstr}{cyc}.nc4" obs_files.append((obs_filename,ob)) - obs_list = [] + obs_files_to_copy = [] obs_to_use = [] # copy obs from COM_OBS to DATA/obs for obs_file, ob in obs_files: logger.info(f"******* {obs_file}") obs_src = path.join(self.config.COM_OBS, obs_file) - obs_dst = path.join(self.runtime_config.DATA, obs_file) + obs_dst = path.join(DATA, obs_file) logger.info(f"******* {obs_src}") if path.exists(obs_src): logger.info(f"******* fetching {obs_file}") - obs_list.append([obs_src, obs_dst]) + obs_files_to_copy.append([obs_src, obs_dst]) obs_to_use.append(ob) else: logger.info(f"******* {obs_file} is not in the database") - FileHandler({'copy': obs_list}).sync() + FileHandler({'copy': obs_files_to_copy}).sync() + # make the letkf.yaml letkf_yaml = parse_j2yaml(self.config.letkf_yaml_template, self.config) letkf_yaml.observations.observers = obs_to_use letkf_yaml.save(self.config.letkf_yaml_file) From 0fca7cd6c2cff3ad28eed4ad725d537ca76e3dda Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 23 May 2024 21:01:32 +0000 Subject: [PATCH 21/50] rearranging --- ush/python/pygfs/task/marine_letkf.py | 108 +++++++++++++++++--------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 4971f52cec..952e459202 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -2,6 +2,7 @@ from datetime import timedelta import f90nml +from glob import glob from logging import getLogger from os import path from pygfs.task.analysis import Analysis @@ -45,6 +46,7 @@ def __init__(self, config: Dict) -> None: PDY = self.runtime_config['PDY'] cyc = self.runtime_config['cyc'] gcyc = str(self.config['gcyc']).zfill(2) + self.runtime_config.gcyc = gcyc gPDY = self.config['gPDY'] RUN = self.runtime_config.RUN DATA = self.runtime_config.DATA @@ -58,21 +60,6 @@ def __init__(self, config: Dict) -> None: window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') - gdate = cdate - timedelta(hours=6) - self.runtime_config['gcyc'] = gdate.strftime("%H") - - self.stage_config = AttrDict( - {'window_begin': f"{window_begin.strftime('%Y-%m-%dT%H:%M:%SZ')}", - 'ATM_WINDOW_BEGIN': window_begin_iso, - 'ATM_WINDOW_MIDDLE': window_middle_iso, - 'DATA': DATA, - 'dump': self.runtime_config.RUN, - 'fv3jedi_stage_files': self.config.FV3JEDI_STAGE_YAML, - 'fv3jedi_stage': self.config.FV3JEDI_STAGE_YAML, - 'stage_dir': DATA, - 'soca_input_fix_dir': self.config.SOCA_INPUT_FIX_DIR, - 'NMEM_ENS': self.config.NMEM_ENS, - 'ATM_WINDOW_LENGTH': f"PT{config['assim_freq']}H"}) self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') self.config['letkf_yaml_file'] = path.join(DATA, 'letkf.yaml') @@ -88,8 +75,9 @@ def __init__(self, config: Dict) -> None: self.config.mom_input_nml_tmpl = path.join(DATA, 'mom_input.nml.tmpl') self.config.mom_input_nml = path.join(DATA, 'mom_input.nml') - self.config.data_output = 'data_output' + self.config.data_output_dir = 'data_output' self.config.ens_dir = 'ens' + self.config.obs_dir = 'obs' self.config.ATM_WINDOW_BEGIN = window_begin_iso self.config.ATM_WINDOW_MIDDLE = window_middle_iso @@ -100,7 +88,7 @@ def __init__(self, config: Dict) -> None: # create list of subdirs to make in initialize, and list of some of the files to stage ens_bkg_files_to_stage = [] - dirs_to_make = [self.config.bkg_dir, self.config.data_output] + dirs_to_make = [self.config.bkg_dir, self.config.data_output_dir, self.config.obs_dir] for mem in range(1,self.config.NMEM_ENS+1): mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 dirs_to_make.append(path.join(self.config.ens_dir,mem_dir)) @@ -161,6 +149,7 @@ def initialize(self): window_begin=self.config.window_begin, yaml_name=self.config.BKG_LIST) + # TODO(AFE): probably needs to be jinjafied obs_list = YAMLFile(self.config.OBS_YAML) # get the list of observations @@ -176,7 +165,7 @@ def initialize(self): for obs_file, ob in obs_files: logger.info(f"******* {obs_file}") obs_src = path.join(self.config.COM_OBS, obs_file) - obs_dst = path.join(DATA, obs_file) + obs_dst = path.join(DATA, self.config.obs_dir, obs_file) logger.info(f"******* {obs_src}") if path.exists(obs_src): logger.info(f"******* fetching {obs_file}") @@ -192,30 +181,14 @@ def initialize(self): letkf_yaml.observations.observers = obs_to_use letkf_yaml.save(self.config.letkf_yaml_file) - @logit(logger) - def run(self): - """Method run for ocean and sea ice LETKF task - Parameters: - ------------ - None - Returns: - -------- - None - """ - - logger.info("run") - - chdir(self.runtime_config.DATA) - FileHandler({'copy': [[self.config.mom_input_nml_src, self.config.mom_input_nml_tmpl]]}).sync() - ufsda.stage.soca_fix(self.stage_config) + self.stage_fix_files() bkg_utils.stage_ic(self.config.bkg_dir, self.runtime_config.DATA, self.runtime_config.gcyc) # swap date and stack size - #domain_stack_size = os.getenv('DOMAIN_STACK_SIZE') domain_stack_size = self.config.DOMAIN_STACK_SIZE ymdhms = [int(s) for s in self.config.window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')] with open(self.config.mom_input_nml_tmpl, 'r') as nml_file: @@ -225,7 +198,20 @@ def run(self): ufsda.disk_utils.removefile(self.config.mom_input_nml) nml.write(self.config.mom_input_nml) - + + @logit(logger) + def run(self): + """Method run for ocean and sea ice LETKF task + Parameters: + ------------ + None + Returns: + -------- + None + """ + + logger.info("run") + exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) exec_cmd_gridgen.add_default_arg(self.config.exec_name_gridgen) exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) @@ -252,3 +238,53 @@ def finalize(self): """ logger.info("finalize") + + @logit(logger) + def stage_fix_files(self): + """Stage fixed files for marine DA + Parameters: + ------------ + None + Returns: + -------- + None + """ + # adapted from ufsda stage_fix + #TODO(AFE): this method maybe should go in a different class + + logger.info("stage_fix_files") + + DATA = self.runtime_config.DATA + SOCA_INPUT_FIX_DIR = self.config.SOCA_INPUT_FIX_DIR + + fix_files = [] + # copy Rossby Radius file + fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'rossrad.dat'), + path.join(DATA, 'rossrad.dat')]) + # link name lists + fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'field_table'), + path.join(DATA, 'field_table')]) + fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'diag_table'), + path.join(DATA, 'diag_table')]) + fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'MOM_input'), + path.join(DATA, 'MOM_input')]) + # link field metadata + fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'fields_metadata.yaml'), + path.join(DATA, 'fields_metadata.yaml')]) + + # link ufo <---> soca name variable mapping + fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'obsop_name_map.yaml'), + path.join(DATA, 'obsop_name_map.yaml')]) + + # INPUT + src_input_dir = path.join(SOCA_INPUT_FIX_DIR, 'INPUT') + dst_input_dir = path.join(DATA, 'INPUT') + FileHandler({'mkdir': [dst_input_dir]}).sync() + + input_files = glob(f'{src_input_dir}/*') + for input_file in input_files: + fname = path.basename(input_file) + fix_files.append([path.join(src_input_dir, fname), + path.join(dst_input_dir, fname)]) + + FileHandler({'copy': fix_files}).sync() \ No newline at end of file From 4a2662b20fe644b2dc188ef99d72c4d5e6631a54 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 28 May 2024 16:57:18 +0000 Subject: [PATCH 22/50] getting to run --- ush/python/pygfs/task/marine_letkf.py | 32 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 952e459202..06ef85fa24 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -9,14 +9,10 @@ from soca import bkg_utils from typing import Dict import ufsda -from ufsda.stage import soca_fix -from wxflow import (AttrDict, - chdir, - Executable, +from wxflow import (Executable, FileHandler, logit, parse_j2yaml, - Task, WorkflowException, YAMLFile) @@ -54,15 +50,19 @@ def __init__(self, config: Dict) -> None: COM_TOP_PREV_ENS = self.config.COM_TOP_PREV_ENS gdas_home = path.join(config['HOMEgfs'], 'sorc', 'gdas.cd') - + exec_dir = path.join(gdas_home, 'build', 'bin') + half_assim_freq = timedelta(hours=int(config['assim_freq'])/2) window_begin = cdate - half_assim_freq window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') - letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') + self.config.letkf_exec = path.join(exec_dir, 'gdas.x') + letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') - self.config['letkf_yaml_file'] = path.join(DATA, 'letkf.yaml') + letkf_yaml_file = path.join(DATA, 'letkf.yaml') + self.config.letkf_exec_args = f"fv3jedi localensembleda {letkf_yaml_file}" + self.config.letkf_yaml_file = letkf_yaml_file self.config['window_begin'] = window_begin self.config['BKG_LIST'] = 'bkg_list.yaml' @@ -116,9 +116,6 @@ def __init__(self, config: Dict) -> None: self.config.ens_bkg_files_to_stage = ens_bkg_files_to_stage self.config.dirs_to_make = dirs_to_make - - - @logit(logger) def initialize(self): """Method initialize for ocean and sea ice LETKF task @@ -225,6 +222,19 @@ def run(self): raise WorkflowException(f"An error occured during execution of {exec_cmd_gridgen}") pass + exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) + exec_cmd_letkf.add_default_arg(self.config.letkf_exec) + exec_cmd_letkf.add_default_arg(self.config.letkf_exec_args ) + + try: + logger.debug(f"Executing {exec_cmd_letkf}") + exec_cmd_letkf() + except OSError: + raise OSError(f"Failed to execute {exec_cmd_letkf}") + except Exception: + raise WorkflowException(f"An error occured during execution of {exec_cmd_letkf}") + pass + @logit(logger) def finalize(self): From 3b9a6888f666fa15cdb500883eafa8859869dd2d Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 28 May 2024 20:39:13 +0000 Subject: [PATCH 23/50] letkf yaml gets ingested --- ush/python/pygfs/task/marine_letkf.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 06ef85fa24..2fce9d89b6 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -39,13 +39,12 @@ def __init__(self, config: Dict) -> None: logger.info("init") super().__init__(config) - PDY = self.runtime_config['PDY'] - cyc = self.runtime_config['cyc'] - gcyc = str(self.config['gcyc']).zfill(2) + PDY = self.runtime_config.PDY + cyc = self.runtime_config.cyc + gcyc = str(self.config.gcyc).zfill(2) self.runtime_config.gcyc = gcyc - gPDY = self.config['gPDY'] RUN = self.runtime_config.RUN - DATA = self.runtime_config.DATA + DATA = path.realpath(self.runtime_config.DATA) cdate = PDY + timedelta(hours=cyc) COM_TOP_PREV_ENS = self.config.COM_TOP_PREV_ENS @@ -56,6 +55,8 @@ def __init__(self, config: Dict) -> None: window_begin = cdate - half_assim_freq window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') + self.config.ATM_WINDOW_BEGIN = window_begin_iso + self.config.ATM_WINDOW_MIDDLE = window_middle_iso self.config.letkf_exec = path.join(exec_dir, 'gdas.x') letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') @@ -75,12 +76,9 @@ def __init__(self, config: Dict) -> None: self.config.mom_input_nml_tmpl = path.join(DATA, 'mom_input.nml.tmpl') self.config.mom_input_nml = path.join(DATA, 'mom_input.nml') - self.config.data_output_dir = 'data_output' - self.config.ens_dir = 'ens' - self.config.obs_dir = 'obs' - - self.config.ATM_WINDOW_BEGIN = window_begin_iso - self.config.ATM_WINDOW_MIDDLE = window_middle_iso + self.config.data_output_dir = path.join(DATA, 'data_output') + self.config.ens_dir = path.join(DATA, 'ens') + self.config.obs_dir = path.join(DATA, 'obs') # set up lists of files for ens background ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{gcyc}z.inst.f009.nc" @@ -224,7 +222,10 @@ def run(self): exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) exec_cmd_letkf.add_default_arg(self.config.letkf_exec) - exec_cmd_letkf.add_default_arg(self.config.letkf_exec_args ) +# exec_cmd_letkf.add_default_arg(self.config.letkf_exec_args ) + exec_cmd_letkf.add_default_arg('fv3jedi') + exec_cmd_letkf.add_default_arg('localensembleda') + exec_cmd_letkf.add_default_arg(self.config.letkf_yaml_file ) try: logger.debug(f"Executing {exec_cmd_letkf}") From 0aded50ec0d8b0f8d671ba844ca4165d6e0fa949 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 28 May 2024 21:03:02 +0000 Subject: [PATCH 24/50] letkf yaml gets ingested better --- ush/python/pygfs/task/marine_letkf.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 2fce9d89b6..fb539e4cf6 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -58,11 +58,15 @@ def __init__(self, config: Dict) -> None: self.config.ATM_WINDOW_BEGIN = window_begin_iso self.config.ATM_WINDOW_MIDDLE = window_middle_iso - self.config.letkf_exec = path.join(exec_dir, 'gdas.x') +# self.config.letkf_exec = path.join(exec_dir, 'gdas.x') + letkf_exec = path.join(exec_dir, 'gdas.x') letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') letkf_yaml_file = path.join(DATA, 'letkf.yaml') - self.config.letkf_exec_args = f"fv3jedi localensembleda {letkf_yaml_file}" + self.config.letkf_exec_args = [letkf_exec, + 'fv3jedi', + 'localensembleda', + letkf_yaml_file] self.config.letkf_yaml_file = letkf_yaml_file self.config['window_begin'] = window_begin @@ -221,11 +225,13 @@ def run(self): pass exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) - exec_cmd_letkf.add_default_arg(self.config.letkf_exec) -# exec_cmd_letkf.add_default_arg(self.config.letkf_exec_args ) - exec_cmd_letkf.add_default_arg('fv3jedi') - exec_cmd_letkf.add_default_arg('localensembleda') - exec_cmd_letkf.add_default_arg(self.config.letkf_yaml_file ) + for letkf_exec_arg in self.config.letkf_exec_args: + exec_cmd_letkf.add_default_arg(letkf_exec_arg) + + # exec_cmd_letkf.add_default_arg(self.config.letkf_exec) + # exec_cmd_letkf.add_default_arg('fv3jedi') + # exec_cmd_letkf.add_default_arg('localensembleda') + # exec_cmd_letkf.add_default_arg(self.config.letkf_yaml_file ) try: logger.debug(f"Executing {exec_cmd_letkf}") From e9d4b310e1b47ff964b9827148ec92999a10cf5e Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 13:45:22 +0000 Subject: [PATCH 25/50] var cleanup --- ush/python/pygfs/task/marine_letkf.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index fb539e4cf6..3294536441 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -47,19 +47,18 @@ def __init__(self, config: Dict) -> None: DATA = path.realpath(self.runtime_config.DATA) cdate = PDY + timedelta(hours=cyc) COM_TOP_PREV_ENS = self.config.COM_TOP_PREV_ENS + JEDI_BIN = self.config.JEDI_BIN - gdas_home = path.join(config['HOMEgfs'], 'sorc', 'gdas.cd') - exec_dir = path.join(gdas_home, 'build', 'bin') + gdas_home = path.join(self.config.HOMEgfs, 'sorc', 'gdas.cd') - half_assim_freq = timedelta(hours=int(config['assim_freq'])/2) + half_assim_freq = timedelta(hours=int(self.config.assim_freq)/2) window_begin = cdate - half_assim_freq window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') self.config.ATM_WINDOW_BEGIN = window_begin_iso self.config.ATM_WINDOW_MIDDLE = window_middle_iso -# self.config.letkf_exec = path.join(exec_dir, 'gdas.x') - letkf_exec = path.join(exec_dir, 'gdas.x') + letkf_exec = path.join(JEDI_BIN, 'gdas.x') letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') letkf_yaml_file = path.join(DATA, 'letkf.yaml') @@ -69,12 +68,12 @@ def __init__(self, config: Dict) -> None: letkf_yaml_file] self.config.letkf_yaml_file = letkf_yaml_file - self.config['window_begin'] = window_begin - self.config['BKG_LIST'] = 'bkg_list.yaml' - self.config['bkg_dir'] = path.join(DATA, 'bkg') + self.config.window_begin = window_begin + self.config.BKG_LIST = 'bkg_list.yaml' + self.config.bkg_dir = path.join(DATA, 'bkg') - self.config.exec_name_gridgen = path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') - self.config['gridgen_yaml'] = path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml') + self.config.exec_name_gridgen = path.join(JEDI_BIN, 'gdas_soca_gridgen.x') + self.config.gridgen_yaml = path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml') self.config.mom_input_nml_src = path.join(gdas_home, 'parm', 'soca', 'fms', 'input.nml') self.config.mom_input_nml_tmpl = path.join(DATA, 'mom_input.nml.tmpl') @@ -228,11 +227,6 @@ def run(self): for letkf_exec_arg in self.config.letkf_exec_args: exec_cmd_letkf.add_default_arg(letkf_exec_arg) - # exec_cmd_letkf.add_default_arg(self.config.letkf_exec) - # exec_cmd_letkf.add_default_arg('fv3jedi') - # exec_cmd_letkf.add_default_arg('localensembleda') - # exec_cmd_letkf.add_default_arg(self.config.letkf_yaml_file ) - try: logger.debug(f"Executing {exec_cmd_letkf}") exec_cmd_letkf() From 980fee2ab537e0fce1f6fc16af8efb60a4b18498 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 14:34:38 +0000 Subject: [PATCH 26/50] removed contents of run method --- ush/python/pygfs/task/marine_letkf.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 3294536441..b16b0cf5c5 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -210,32 +210,6 @@ def run(self): logger.info("run") - exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) - exec_cmd_gridgen.add_default_arg(self.config.exec_name_gridgen) - exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) - - try: - logger.debug(f"Executing {exec_cmd_gridgen}") - exec_cmd_gridgen() - except OSError: - raise OSError(f"Failed to execute {exec_cmd_gridgen}") - except Exception: - raise WorkflowException(f"An error occured during execution of {exec_cmd_gridgen}") - pass - - exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) - for letkf_exec_arg in self.config.letkf_exec_args: - exec_cmd_letkf.add_default_arg(letkf_exec_arg) - - try: - logger.debug(f"Executing {exec_cmd_letkf}") - exec_cmd_letkf() - except OSError: - raise OSError(f"Failed to execute {exec_cmd_letkf}") - except Exception: - raise WorkflowException(f"An error occured during execution of {exec_cmd_letkf}") - pass - @logit(logger) def finalize(self): From 024cb330e24e322e8ed45857b72cd1743af81ae6 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 14:43:08 +0000 Subject: [PATCH 27/50] removed keepdata --- parm/config/gfs/config.ocnanalletkf | 2 -- 1 file changed, 2 deletions(-) diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.ocnanalletkf index 239dc7d453..b67f37152e 100644 --- a/parm/config/gfs/config.ocnanalletkf +++ b/parm/config/gfs/config.ocnanalletkf @@ -8,6 +8,4 @@ echo "BEGIN: config.ocnanalletkf" # Get task specific resources . "${EXPDIR}/config.resources" ocnanalletkf -KEEPDATA="YES" - echo "END: config.ocnanalletkf" From 978f7214ee87e4ef2928975eef02fec3b6a9d59e Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 15:00:18 +0000 Subject: [PATCH 28/50] style --- ush/python/pygfs/task/marine_letkf.py | 28 +++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 3294536441..b770819c69 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -2,7 +2,7 @@ from datetime import timedelta import f90nml -from glob import glob +from glob import glob from logging import getLogger from os import path from pygfs.task.analysis import Analysis @@ -50,8 +50,8 @@ def __init__(self, config: Dict) -> None: JEDI_BIN = self.config.JEDI_BIN gdas_home = path.join(self.config.HOMEgfs, 'sorc', 'gdas.cd') - - half_assim_freq = timedelta(hours=int(self.config.assim_freq)/2) + + half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) window_begin = cdate - half_assim_freq window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') @@ -62,7 +62,7 @@ def __init__(self, config: Dict) -> None: letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') letkf_yaml_file = path.join(DATA, 'letkf.yaml') - self.config.letkf_exec_args = [letkf_exec, + self.config.letkf_exec_args = [letkf_exec, 'fv3jedi', 'localensembleda', letkf_yaml_file] @@ -90,9 +90,9 @@ def __init__(self, config: Dict) -> None: # create list of subdirs to make in initialize, and list of some of the files to stage ens_bkg_files_to_stage = [] dirs_to_make = [self.config.bkg_dir, self.config.data_output_dir, self.config.obs_dir] - for mem in range(1,self.config.NMEM_ENS+1): - mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 - dirs_to_make.append(path.join(self.config.ens_dir,mem_dir)) + for mem in range(1, self.config.NMEM_ENS+1): + mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 + dirs_to_make.append(path.join(self.config.ens_dir, mem_dir)) ocn_file_path = path.join(COM_TOP_PREV_ENS, mem_dir, 'model_data', @@ -140,7 +140,7 @@ def initialize(self): FileHandler({'mkdir': self.config.dirs_to_make}).sync() # copy ensemble background to DATA/ens/mem??? - FileHandler({'copy': self.config.ens_bkg_files_to_stage }).sync() + FileHandler({'copy': self.config.ens_bkg_files_to_stage}).sync() bkg_utils.gen_bkg_list(bkg_path=self.config.COM_OCEAN_HISTORY_PREV, out_path=self.config.bkg_dir, @@ -155,7 +155,7 @@ def initialize(self): for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() obs_filename = f"{RUN}.t{cyc}z.{obs_name}.{PDYstr}{cyc}.nc4" - obs_files.append((obs_filename,ob)) + obs_files.append((obs_filename, ob)) obs_files_to_copy = [] obs_to_use = [] @@ -180,8 +180,8 @@ def initialize(self): letkf_yaml.save(self.config.letkf_yaml_file) FileHandler({'copy': [[self.config.mom_input_nml_src, - self.config.mom_input_nml_tmpl]]}).sync() - + self.config.mom_input_nml_tmpl]]}).sync() + self.stage_fix_files() bkg_utils.stage_ic(self.config.bkg_dir, self.runtime_config.DATA, self.runtime_config.gcyc) @@ -195,7 +195,6 @@ def initialize(self): nml['fms_nml']['domains_stack_size'] = int(domain_stack_size) ufsda.disk_utils.removefile(self.config.mom_input_nml) nml.write(self.config.mom_input_nml) - @logit(logger) def run(self): @@ -236,7 +235,6 @@ def run(self): raise WorkflowException(f"An error occured during execution of {exec_cmd_letkf}") pass - @logit(logger) def finalize(self): """Method finalize for ocean and sea ice LETKF task @@ -286,12 +284,12 @@ def stage_fix_files(self): # link ufo <---> soca name variable mapping fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'obsop_name_map.yaml'), path.join(DATA, 'obsop_name_map.yaml')]) - + # INPUT src_input_dir = path.join(SOCA_INPUT_FIX_DIR, 'INPUT') dst_input_dir = path.join(DATA, 'INPUT') FileHandler({'mkdir': [dst_input_dir]}).sync() - + input_files = glob(f'{src_input_dir}/*') for input_file in input_files: fname = path.basename(input_file) From 961cd60e089d10509282742fa78826c912b22b21 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 18:00:54 +0000 Subject: [PATCH 29/50] style --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 2 +- ush/python/pygfs/task/marine_letkf.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index d21537e4cd..e06b280dd3 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -9,7 +9,7 @@ source "${HOMEgfs}/ush/jjob_header.sh" -e "ocnanalletkf" -c "base ocnanal ocnana # shellcheck disable=SC2153 GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") -export gPDY=${GDATE:0:8} +gPDY=${GDATE:0:8} gcyc=${GDATE:8:2} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 9496b8e449..a5b3f0b121 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -63,9 +63,9 @@ def __init__(self, config: Dict) -> None: self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') letkf_yaml_file = path.join(DATA, 'letkf.yaml') self.config.letkf_exec_args = [letkf_exec, - 'fv3jedi', - 'localensembleda', - letkf_yaml_file] + 'fv3jedi', + 'localensembleda', + letkf_yaml_file] self.config.letkf_yaml_file = letkf_yaml_file self.config.window_begin = window_begin @@ -90,7 +90,7 @@ def __init__(self, config: Dict) -> None: # create list of subdirs to make in initialize, and list of some of the files to stage ens_bkg_files_to_stage = [] dirs_to_make = [self.config.bkg_dir, self.config.data_output_dir, self.config.obs_dir] - for mem in range(1, self.config.NMEM_ENS+1): + for mem in range(1, self.config.NMEM_ENS + 1): mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 dirs_to_make.append(path.join(self.config.ens_dir, mem_dir)) ocn_file_path = path.join(COM_TOP_PREV_ENS, @@ -233,7 +233,7 @@ def stage_fix_files(self): None """ # adapted from ufsda stage_fix - #TODO(AFE): this method maybe should go in a different class + # TODO(AFE): this method maybe should go in a different class logger.info("stage_fix_files") @@ -254,7 +254,7 @@ def stage_fix_files(self): # link field metadata fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'fields_metadata.yaml'), path.join(DATA, 'fields_metadata.yaml')]) - + # link ufo <---> soca name variable mapping fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'obsop_name_map.yaml'), path.join(DATA, 'obsop_name_map.yaml')]) @@ -269,5 +269,5 @@ def stage_fix_files(self): fname = path.basename(input_file) fix_files.append([path.join(src_input_dir, fname), path.join(dst_input_dir, fname)]) - + FileHandler({'copy': fix_files}).sync() From 1039b75c6238b13e0fc82c1a6ec76a015f2dde8d Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 18:06:50 +0000 Subject: [PATCH 30/50] style --- ush/python/pygfs/task/marine_letkf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index a5b3f0b121..ff3b59db40 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -254,7 +254,7 @@ def stage_fix_files(self): # link field metadata fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'fields_metadata.yaml'), path.join(DATA, 'fields_metadata.yaml')]) - + # link ufo <---> soca name variable mapping fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'obsop_name_map.yaml'), path.join(DATA, 'obsop_name_map.yaml')]) From 7841058097baddeb7254057d692d1c0e63f73543 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 29 May 2024 18:12:56 +0000 Subject: [PATCH 31/50] add back run --- ush/python/pygfs/task/marine_letkf.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index ff3b59db40..8c080b02e9 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -209,6 +209,32 @@ def run(self): logger.info("run") + exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) + exec_cmd_gridgen.add_default_arg(self.config.exec_name_gridgen) + exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) + + try: + logger.debug(f"Executing {exec_cmd_gridgen}") + exec_cmd_gridgen() + except OSError: + raise OSError(f"Failed to execute {exec_cmd_gridgen}") + except Exception: + raise WorkflowException(f"An error occured during execution of {exec_cmd_gridgen}") + pass + + exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) + for letkf_exec_arg in self.config.letkf_exec_args: + exec_cmd_letkf.add_default_arg(letkf_exec_arg) + + try: + logger.debug(f"Executing {exec_cmd_letkf}") + exec_cmd_letkf() + except OSError: + raise OSError(f"Failed to execute {exec_cmd_letkf}") + except Exception: + raise WorkflowException(f"An error occured during execution of {exec_cmd_letkf}") + pass + @logit(logger) def finalize(self): """Method finalize for ocean and sea ice LETKF task From eda6827a00030b62f9e55bef374c240e936294df Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 30 May 2024 15:52:46 +0000 Subject: [PATCH 32/50] merge to develop --- ush/python/pygfs/task/marine_letkf.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 8c080b02e9..ff3b59db40 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -209,32 +209,6 @@ def run(self): logger.info("run") - exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) - exec_cmd_gridgen.add_default_arg(self.config.exec_name_gridgen) - exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) - - try: - logger.debug(f"Executing {exec_cmd_gridgen}") - exec_cmd_gridgen() - except OSError: - raise OSError(f"Failed to execute {exec_cmd_gridgen}") - except Exception: - raise WorkflowException(f"An error occured during execution of {exec_cmd_gridgen}") - pass - - exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) - for letkf_exec_arg in self.config.letkf_exec_args: - exec_cmd_letkf.add_default_arg(letkf_exec_arg) - - try: - logger.debug(f"Executing {exec_cmd_letkf}") - exec_cmd_letkf() - except OSError: - raise OSError(f"Failed to execute {exec_cmd_letkf}") - except Exception: - raise WorkflowException(f"An error occured during execution of {exec_cmd_letkf}") - pass - @logit(logger) def finalize(self): """Method finalize for ocean and sea ice LETKF task From 64c323a23150505bc620eaf1e4b505ed224f9f47 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 31 May 2024 18:05:54 +0000 Subject: [PATCH 33/50] more cleanup --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 1 - ush/python/pygfs/task/marine_letkf.py | 167 ++++++------------------- 2 files changed, 35 insertions(+), 133 deletions(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index e06b280dd3..51ad5d7743 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -17,7 +17,6 @@ YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COM_OBS -ROTDIR=${COMROOT} RUN=enkf${RUN} YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx COM_TOP_PREV_ENS:COM_TOP_TMPL ############################################## # Begin JOB SPECIFIC work diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 8c080b02e9..1222a59bb0 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -9,7 +9,8 @@ from soca import bkg_utils from typing import Dict import ufsda -from wxflow import (Executable, +from wxflow import (AttrDict, + Executable, FileHandler, logit, parse_j2yaml, @@ -39,28 +40,23 @@ def __init__(self, config: Dict) -> None: logger.info("init") super().__init__(config) - PDY = self.runtime_config.PDY - cyc = self.runtime_config.cyc - gcyc = str(self.config.gcyc).zfill(2) - self.runtime_config.gcyc = gcyc + self.config.gcyc = self.runtime_config.previous_cycle.strftime('%H') RUN = self.runtime_config.RUN DATA = path.realpath(self.runtime_config.DATA) - cdate = PDY + timedelta(hours=cyc) - COM_TOP_PREV_ENS = self.config.COM_TOP_PREV_ENS - JEDI_BIN = self.config.JEDI_BIN gdas_home = path.join(self.config.HOMEgfs, 'sorc', 'gdas.cd') half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) - window_begin = cdate - half_assim_freq + window_begin = self.runtime_config.current_cycle - half_assim_freq window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') - window_middle_iso = cdate.strftime('%Y-%m-%dT%H:%M:%SZ') + window_middle_iso = self.runtime_config.current_cycle.strftime('%Y-%m-%dT%H:%M:%SZ') self.config.ATM_WINDOW_BEGIN = window_begin_iso self.config.ATM_WINDOW_MIDDLE = window_middle_iso - letkf_exec = path.join(JEDI_BIN, 'gdas.x') + letkf_exec = path.join(self.config.JEDI_BIN, 'gdas.x') letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') + self.config['letkf_stage_yaml_template'] = path.join(letkf_yaml_dir, 'letkf_stage.yaml.j2') letkf_yaml_file = path.join(DATA, 'letkf.yaml') self.config.letkf_exec_args = [letkf_exec, 'fv3jedi', @@ -72,7 +68,7 @@ def __init__(self, config: Dict) -> None: self.config.BKG_LIST = 'bkg_list.yaml' self.config.bkg_dir = path.join(DATA, 'bkg') - self.config.exec_name_gridgen = path.join(JEDI_BIN, 'gdas_soca_gridgen.x') + self.config.exec_name_gridgen = path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') self.config.gridgen_yaml = path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml') self.config.mom_input_nml_src = path.join(gdas_home, 'parm', 'soca', 'fms', 'input.nml') @@ -84,38 +80,11 @@ def __init__(self, config: Dict) -> None: self.config.obs_dir = path.join(DATA, 'obs') # set up lists of files for ens background - ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{gcyc}z.inst.f009.nc" - ice_ens_bkg_filename = f"enkf{RUN}.ice.t{gcyc}z.inst.f009.nc" - - # create list of subdirs to make in initialize, and list of some of the files to stage - ens_bkg_files_to_stage = [] - dirs_to_make = [self.config.bkg_dir, self.config.data_output_dir, self.config.obs_dir] - for mem in range(1, self.config.NMEM_ENS + 1): - mem_dir = f'mem{str(mem).zfill(3)}' # will make pattern mem001 - dirs_to_make.append(path.join(self.config.ens_dir, mem_dir)) - ocn_file_path = path.join(COM_TOP_PREV_ENS, - mem_dir, - 'model_data', - 'ocean', - 'history', - ocn_ens_bkg_filename) - ocn_file_dest = path.join(self.config.ens_dir, - mem_dir, - ocn_ens_bkg_filename) - ice_file_path = path.join(COM_TOP_PREV_ENS, - mem_dir, - 'model_data', - 'ice', - 'history', - ice_ens_bkg_filename) - ice_file_dest = path.join(self.config.ens_dir, - mem_dir, - ice_ens_bkg_filename) - ens_bkg_files_to_stage.append((ocn_file_path, ocn_file_dest)) - ens_bkg_files_to_stage.append((ice_file_path, ice_file_dest)) - - self.config.ens_bkg_files_to_stage = ens_bkg_files_to_stage - self.config.dirs_to_make = dirs_to_make + self.config.ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{self.config.gcyc}z.inst.f009.nc" + self.config.ice_ens_bkg_filename = f"enkf{RUN}.ice.t{self.config.gcyc}z.inst.f009.nc" + + self.task_config = AttrDict(dict(**self.config, **self.runtime_config)) + @logit(logger) def initialize(self): @@ -130,31 +99,19 @@ def initialize(self): logger.info("initialize") - cyc = self.runtime_config.cyc - DATA = self.runtime_config.DATA - ens_dir = self.config.ens_dir - PDYstr = self.runtime_config.PDY.strftime("%Y%m%d") - RUN = self.runtime_config.RUN - - # create directories under DATA - FileHandler({'mkdir': self.config.dirs_to_make}).sync() - - # copy ensemble background to DATA/ens/mem??? - FileHandler({'copy': self.config.ens_bkg_files_to_stage}).sync() - - bkg_utils.gen_bkg_list(bkg_path=self.config.COM_OCEAN_HISTORY_PREV, - out_path=self.config.bkg_dir, - window_begin=self.config.window_begin, - yaml_name=self.config.BKG_LIST) + # make directories and stage ensemble background files + letkf_stage_list = parse_j2yaml(self.task_config.letkf_stage_yaml_template, self.task_config) + FileHandler(letkf_stage_list).sync() # TODO(AFE): probably needs to be jinjafied - obs_list = YAMLFile(self.config.OBS_YAML) + obs_list = YAMLFile(self.task_config.OBS_YAML) # get the list of observations + CDATE = self.runtime_config.current_cycle.strftime("%Y%m%d%H") obs_files = [] for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() - obs_filename = f"{RUN}.t{cyc}z.{obs_name}.{PDYstr}{cyc}.nc4" + obs_filename = f"{self.task_config.RUN}.t{self.task_config.cyc}z.{obs_name}.{CDATE}.nc4" obs_files.append((obs_filename, ob)) obs_files_to_copy = [] @@ -162,8 +119,8 @@ def initialize(self): # copy obs from COM_OBS to DATA/obs for obs_file, ob in obs_files: logger.info(f"******* {obs_file}") - obs_src = path.join(self.config.COM_OBS, obs_file) - obs_dst = path.join(DATA, self.config.obs_dir, obs_file) + obs_src = path.join(self.task_config.COM_OBS, obs_file) + obs_dst = path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) logger.info(f"******* {obs_src}") if path.exists(obs_src): logger.info(f"******* fetching {obs_file}") @@ -175,26 +132,22 @@ def initialize(self): FileHandler({'copy': obs_files_to_copy}).sync() # make the letkf.yaml - letkf_yaml = parse_j2yaml(self.config.letkf_yaml_template, self.config) + letkf_yaml = parse_j2yaml(self.task_config.letkf_yaml_template, self.task_config) letkf_yaml.observations.observers = obs_to_use - letkf_yaml.save(self.config.letkf_yaml_file) - - FileHandler({'copy': [[self.config.mom_input_nml_src, - self.config.mom_input_nml_tmpl]]}).sync() + letkf_yaml.save(self.task_config.letkf_yaml_file) - self.stage_fix_files() - - bkg_utils.stage_ic(self.config.bkg_dir, self.runtime_config.DATA, self.runtime_config.gcyc) + FileHandler({'copy': [[self.task_config.mom_input_nml_src, + self.task_config.mom_input_nml_tmpl]]}).sync() # swap date and stack size - domain_stack_size = self.config.DOMAIN_STACK_SIZE - ymdhms = [int(s) for s in self.config.window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')] - with open(self.config.mom_input_nml_tmpl, 'r') as nml_file: + domain_stack_size = self.task_config.DOMAIN_STACK_SIZE + ymdhms = [int(s) for s in self.task_config.window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')] + with open(self.task_config.mom_input_nml_tmpl, 'r') as nml_file: nml = f90nml.read(nml_file) nml['ocean_solo_nml']['date_init'] = ymdhms nml['fms_nml']['domains_stack_size'] = int(domain_stack_size) - ufsda.disk_utils.removefile(self.config.mom_input_nml) - nml.write(self.config.mom_input_nml) + ufsda.disk_utils.removefile(self.task_config.mom_input_nml) + nml.write(self.task_config.mom_input_nml) @logit(logger) def run(self): @@ -209,9 +162,9 @@ def run(self): logger.info("run") - exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALLETKF) - exec_cmd_gridgen.add_default_arg(self.config.exec_name_gridgen) - exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml) + exec_cmd_gridgen = Executable(self.task_config.APRUN_OCNANALLETKF) + exec_cmd_gridgen.add_default_arg(self.task_config.exec_name_gridgen) + exec_cmd_gridgen.add_default_arg(self.task_config.gridgen_yaml) try: logger.debug(f"Executing {exec_cmd_gridgen}") @@ -222,8 +175,8 @@ def run(self): raise WorkflowException(f"An error occured during execution of {exec_cmd_gridgen}") pass - exec_cmd_letkf = Executable(self.config.APRUN_OCNANALLETKF) - for letkf_exec_arg in self.config.letkf_exec_args: + exec_cmd_letkf = Executable(self.task_config.APRUN_OCNANALLETKF) + for letkf_exec_arg in self.task_config.letkf_exec_args: exec_cmd_letkf.add_default_arg(letkf_exec_arg) try: @@ -247,53 +200,3 @@ def finalize(self): """ logger.info("finalize") - - @logit(logger) - def stage_fix_files(self): - """Stage fixed files for marine DA - Parameters: - ------------ - None - Returns: - -------- - None - """ - # adapted from ufsda stage_fix - # TODO(AFE): this method maybe should go in a different class - - logger.info("stage_fix_files") - - DATA = self.runtime_config.DATA - SOCA_INPUT_FIX_DIR = self.config.SOCA_INPUT_FIX_DIR - - fix_files = [] - # copy Rossby Radius file - fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'rossrad.dat'), - path.join(DATA, 'rossrad.dat')]) - # link name lists - fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'field_table'), - path.join(DATA, 'field_table')]) - fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'diag_table'), - path.join(DATA, 'diag_table')]) - fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'MOM_input'), - path.join(DATA, 'MOM_input')]) - # link field metadata - fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'fields_metadata.yaml'), - path.join(DATA, 'fields_metadata.yaml')]) - - # link ufo <---> soca name variable mapping - fix_files.append([path.join(SOCA_INPUT_FIX_DIR, 'obsop_name_map.yaml'), - path.join(DATA, 'obsop_name_map.yaml')]) - - # INPUT - src_input_dir = path.join(SOCA_INPUT_FIX_DIR, 'INPUT') - dst_input_dir = path.join(DATA, 'INPUT') - FileHandler({'mkdir': [dst_input_dir]}).sync() - - input_files = glob(f'{src_input_dir}/*') - for input_file in input_files: - fname = path.basename(input_file) - fix_files.append([path.join(src_input_dir, fname), - path.join(dst_input_dir, fname)]) - - FileHandler({'copy': fix_files}).sync() From e5fc8100cc11f897a4594f604bf57ba57173fc30 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 31 May 2024 20:36:26 +0000 Subject: [PATCH 34/50] tweaks --- parm/config/gfs/config.ocnanalletkf | 7 +++ ush/python/pygfs/task/marine_letkf.py | 84 ++++++++++----------------- 2 files changed, 37 insertions(+), 54 deletions(-) diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.ocnanalletkf index b67f37152e..6dcdcd311b 100644 --- a/parm/config/gfs/config.ocnanalletkf +++ b/parm/config/gfs/config.ocnanalletkf @@ -8,4 +8,11 @@ echo "BEGIN: config.ocnanalletkf" # Get task specific resources . "${EXPDIR}/config.resources" ocnanalletkf +export MARINE_LETKF_EXEC="${JEDI_BIN}/gdas.x" +export MARINE_LETKF_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf.yaml.j2" +export MARINE_LETKF_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf_stage.yaml.j2" + +export GRIDGEN_EXEC="${JEDI_BIN}/gdas_soca_gridgen.x" +export GRIDGEN_YAML="${PARMgfs}/gdas/soca/gridgen/gridgen.yaml" + echo "END: config.ocnanalletkf" diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 1222a59bb0..99e0187bef 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -19,7 +19,6 @@ logger = getLogger(__name__.split('.')[-1]) - class MarineLETKF(Analysis): """ Class for global ocean and sea ice analysis LETKF task @@ -40,51 +39,30 @@ def __init__(self, config: Dict) -> None: logger.info("init") super().__init__(config) - self.config.gcyc = self.runtime_config.previous_cycle.strftime('%H') - RUN = self.runtime_config.RUN - DATA = path.realpath(self.runtime_config.DATA) - - gdas_home = path.join(self.config.HOMEgfs, 'sorc', 'gdas.cd') - - half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) - window_begin = self.runtime_config.current_cycle - half_assim_freq - window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') - window_middle_iso = self.runtime_config.current_cycle.strftime('%Y-%m-%dT%H:%M:%SZ') - self.config.ATM_WINDOW_BEGIN = window_begin_iso - self.config.ATM_WINDOW_MIDDLE = window_middle_iso - - letkf_exec = path.join(self.config.JEDI_BIN, 'gdas.x') - letkf_yaml_dir = path.join(gdas_home, 'parm', 'soca', 'letkf') - self.config['letkf_yaml_template'] = path.join(letkf_yaml_dir, 'letkf.yaml.j2') - self.config['letkf_stage_yaml_template'] = path.join(letkf_yaml_dir, 'letkf_stage.yaml.j2') - letkf_yaml_file = path.join(DATA, 'letkf.yaml') - self.config.letkf_exec_args = [letkf_exec, - 'fv3jedi', - 'localensembleda', - letkf_yaml_file] - self.config.letkf_yaml_file = letkf_yaml_file - - self.config.window_begin = window_begin - self.config.BKG_LIST = 'bkg_list.yaml' - self.config.bkg_dir = path.join(DATA, 'bkg') - - self.config.exec_name_gridgen = path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') - self.config.gridgen_yaml = path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml') - - self.config.mom_input_nml_src = path.join(gdas_home, 'parm', 'soca', 'fms', 'input.nml') - self.config.mom_input_nml_tmpl = path.join(DATA, 'mom_input.nml.tmpl') - self.config.mom_input_nml = path.join(DATA, 'mom_input.nml') - - self.config.data_output_dir = path.join(DATA, 'data_output') - self.config.ens_dir = path.join(DATA, 'ens') - self.config.obs_dir = path.join(DATA, 'obs') - - # set up lists of files for ens background - self.config.ocn_ens_bkg_filename = f"enkf{RUN}.ocean.t{self.config.gcyc}z.inst.f009.nc" - self.config.ice_ens_bkg_filename = f"enkf{RUN}.ice.t{self.config.gcyc}z.inst.f009.nc" - - self.task_config = AttrDict(dict(**self.config, **self.runtime_config)) - + _half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) + _window_begin = self.runtime_config.current_cycle - _half_assim_freq + _window_begin_iso = _window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') + _window_middle_iso = self.runtime_config.current_cycle.strftime('%Y-%m-%dT%H:%M:%SZ') + _letkf_yaml_file = 'letkf.yaml' + _letkf_exec_args = [self.config.MARINE_LETKF_EXEC, + 'fv3jedi', + 'localensembleda', + _letkf_yaml_file] + + local_dict = AttrDict( + { + 'ATM_WINDOW_BEGIN': _window_begin_iso, + 'ATM_WINDOW_MIDDLE': _window_middle_iso, + 'window_begin': _window_begin, + 'letkf_exec_args': _letkf_exec_args, + 'letkf_yaml_file': _letkf_yaml_file, + 'mom_input_nml_tmpl': path.join(self.runtime_config.DATA, 'mom_input.nml.tmpl'), + 'mom_input_nml': path.join(self.runtime_config.DATA, 'mom_input.nml'), + 'obs_dir': path.join(self.runtime_config.DATA, 'obs') + } + ) + + self.task_config = AttrDict(dict(**self.config, **self.runtime_config, **local_dict)) @logit(logger) def initialize(self): @@ -100,7 +78,7 @@ def initialize(self): logger.info("initialize") # make directories and stage ensemble background files - letkf_stage_list = parse_j2yaml(self.task_config.letkf_stage_yaml_template, self.task_config) + letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_list).sync() # TODO(AFE): probably needs to be jinjafied @@ -129,17 +107,15 @@ def initialize(self): else: logger.info(f"******* {obs_file} is not in the database") + # stage the desired obs files FileHandler({'copy': obs_files_to_copy}).sync() # make the letkf.yaml - letkf_yaml = parse_j2yaml(self.task_config.letkf_yaml_template, self.task_config) + letkf_yaml = parse_j2yaml(self.task_config.MARINE_LETKF_YAML_TMPL, self.task_config) letkf_yaml.observations.observers = obs_to_use letkf_yaml.save(self.task_config.letkf_yaml_file) - FileHandler({'copy': [[self.task_config.mom_input_nml_src, - self.task_config.mom_input_nml_tmpl]]}).sync() - - # swap date and stack size + # swap date and stack size in mom_input.nml domain_stack_size = self.task_config.DOMAIN_STACK_SIZE ymdhms = [int(s) for s in self.task_config.window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')] with open(self.task_config.mom_input_nml_tmpl, 'r') as nml_file: @@ -163,8 +139,8 @@ def run(self): logger.info("run") exec_cmd_gridgen = Executable(self.task_config.APRUN_OCNANALLETKF) - exec_cmd_gridgen.add_default_arg(self.task_config.exec_name_gridgen) - exec_cmd_gridgen.add_default_arg(self.task_config.gridgen_yaml) + exec_cmd_gridgen.add_default_arg(self.task_config.GRIDGEN_EXEC) + exec_cmd_gridgen.add_default_arg(self.task_config.GRIDGEN_YAML) try: logger.debug(f"Executing {exec_cmd_gridgen}") From bc2e840a81d169f37254857e365d62dadb35518d Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Mon, 3 Jun 2024 18:25:03 +0000 Subject: [PATCH 35/50] adding GDUMP, GDUMP_ENS --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index 51ad5d7743..d05a013382 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -12,6 +12,9 @@ GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") gPDY=${GDATE:0:8} gcyc=${GDATE:8:2} +export GDUMP=${GDUMP:-"gdas"} +export GDUMP_ENS="enkf${GDUMP}" + YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL From 62b5d4233858fe798c43637ab6f19589bd564cf4 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Mon, 3 Jun 2024 20:58:46 +0000 Subject: [PATCH 36/50] review tweaks --- ush/python/pygfs/task/marine_letkf.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index de86924c4d..d15e64c530 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -2,14 +2,12 @@ from datetime import timedelta import f90nml -from glob import glob from logging import getLogger from os import path from pygfs.task.analysis import Analysis -from soca import bkg_utils from typing import Dict -import ufsda from wxflow import (AttrDict, + datetime_to_YMDH, Executable, FileHandler, logit, @@ -40,9 +38,6 @@ def __init__(self, config: Dict) -> None: super().__init__(config) _half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) - _window_begin = self.runtime_config.current_cycle - _half_assim_freq - _window_begin_iso = _window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') - _window_middle_iso = self.runtime_config.current_cycle.strftime('%Y-%m-%dT%H:%M:%SZ') _letkf_yaml_file = 'letkf.yaml' _letkf_exec_args = [self.config.MARINE_LETKF_EXEC, 'fv3jedi', @@ -51,9 +46,8 @@ def __init__(self, config: Dict) -> None: local_dict = AttrDict( { - 'ATM_WINDOW_BEGIN': _window_begin_iso, - 'ATM_WINDOW_MIDDLE': _window_middle_iso, - 'window_begin': _window_begin, + 'WINDOW_BEGIN': self.runtime_config.current_cycle - _half_assim_freq, + 'WINDOW_MIDDLE': self.runtime_config.current_cycle, 'letkf_exec_args': _letkf_exec_args, 'letkf_yaml_file': _letkf_yaml_file, 'mom_input_nml_tmpl': path.join(self.runtime_config.DATA, 'mom_input.nml.tmpl'), @@ -85,7 +79,7 @@ def initialize(self): obs_list = YAMLFile(self.task_config.OBS_YAML) # get the list of observations - CDATE = self.runtime_config.current_cycle.strftime("%Y%m%d%H") + CDATE = datetime_to_YMDH(self.runtime_config.current_cycle) obs_files = [] for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() @@ -117,13 +111,12 @@ def initialize(self): # swap date and stack size in mom_input.nml domain_stack_size = self.task_config.DOMAIN_STACK_SIZE - ymdhms = [int(s) for s in self.task_config.window_begin.strftime('%Y,%m,%d,%H,%M,%S').split(',')] + ymdhms = [int(s) for s in self.task_config.WINDOW_BEGIN.strftime('%Y,%m,%d,%H,%M,%S').split(',')] with open(self.task_config.mom_input_nml_tmpl, 'r') as nml_file: nml = f90nml.read(nml_file) nml['ocean_solo_nml']['date_init'] = ymdhms nml['fms_nml']['domains_stack_size'] = int(domain_stack_size) - ufsda.disk_utils.removefile(self.task_config.mom_input_nml) - nml.write(self.task_config.mom_input_nml) + nml.write(self.task_config.mom_input_nml, force=True) # force to overwrite if necessary @logit(logger) def run(self): From 500db0f266d447900f8835258192cd2fe1a409ca Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 5 Jun 2024 14:24:18 +0000 Subject: [PATCH 37/50] removed superfluous logging --- ush/python/pygfs/task/marine_letkf.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index d15e64c530..ce96216a77 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -90,16 +90,14 @@ def initialize(self): obs_to_use = [] # copy obs from COM_OBS to DATA/obs for obs_file, ob in obs_files: - logger.info(f"******* {obs_file}") obs_src = path.join(self.task_config.COM_OBS, obs_file) obs_dst = path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) - logger.info(f"******* {obs_src}") if path.exists(obs_src): - logger.info(f"******* fetching {obs_file}") + logger.info(f"will try to stage {obs_file}") obs_files_to_copy.append([obs_src, obs_dst]) obs_to_use.append(ob) else: - logger.info(f"******* {obs_file} is not in the database") + logger.info(f"{obs_file} is not available in {self.task_config.COM_OBS}") # stage the desired obs files FileHandler({'copy': obs_files_to_copy}).sync() From 44ba94bfbcbc05b7a0447961576f22f7645cc0ed Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 5 Jun 2024 21:10:28 +0000 Subject: [PATCH 38/50] style, separated fix file yaml --- parm/config/gfs/config.ocnanal | 1 + ush/python/pygfs/task/marine_letkf.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/parm/config/gfs/config.ocnanal b/parm/config/gfs/config.ocnanal index 38a6cbd52a..537cfd6d64 100644 --- a/parm/config/gfs/config.ocnanal +++ b/parm/config/gfs/config.ocnanal @@ -16,6 +16,7 @@ export SOCA_NINNER=@SOCA_NINNER@ export CASE_ANL=@CASE_ANL@ export DOMAIN_STACK_SIZE=116640000 #TODO: Make the stack size resolution dependent export JEDI_BIN=${HOMEgfs}/sorc/gdas.cd/build/bin +export SOCA_FIX_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/soca_fix_stage.yaml.j2" export COMIN_OBS=@COMIN_OBS@ diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index ce96216a77..0f1b331cbf 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -17,6 +17,7 @@ logger = getLogger(__name__.split('.')[-1]) + class MarineLETKF(Analysis): """ Class for global ocean and sea ice analysis LETKF task @@ -50,7 +51,7 @@ def __init__(self, config: Dict) -> None: 'WINDOW_MIDDLE': self.runtime_config.current_cycle, 'letkf_exec_args': _letkf_exec_args, 'letkf_yaml_file': _letkf_yaml_file, - 'mom_input_nml_tmpl': path.join(self.runtime_config.DATA, 'mom_input.nml.tmpl'), + 'mom_input_nml_tmpl': path.join(self.runtime_config.DATA, 'mom_input.nml.tmpl'), 'mom_input_nml': path.join(self.runtime_config.DATA, 'mom_input.nml'), 'obs_dir': path.join(self.runtime_config.DATA, 'obs') } @@ -74,6 +75,8 @@ def initialize(self): # make directories and stage ensemble background files letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_list).sync() + letkf_stage_fix_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) + FileHandler(letkf_stage_fix_list).sync() # TODO(AFE): probably needs to be jinjafied obs_list = YAMLFile(self.task_config.OBS_YAML) @@ -114,7 +117,7 @@ def initialize(self): nml = f90nml.read(nml_file) nml['ocean_solo_nml']['date_init'] = ymdhms nml['fms_nml']['domains_stack_size'] = int(domain_stack_size) - nml.write(self.task_config.mom_input_nml, force=True) # force to overwrite if necessary + nml.write(self.task_config.mom_input_nml, force=True) # force to overwrite if necessary @logit(logger) def run(self): From cb3921950ce457048a2f4564c771af24eeeaa6e6 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 21 Jun 2024 11:09:24 +0000 Subject: [PATCH 39/50] marine to ocean --- parm/config/gfs/config.ocnanal | 2 -- parm/config/gfs/config.ocnanalletkf | 6 +++--- ush/python/pygfs/task/marine_letkf.py | 8 +++----- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/parm/config/gfs/config.ocnanal b/parm/config/gfs/config.ocnanal index 537cfd6d64..14d24fccbd 100644 --- a/parm/config/gfs/config.ocnanal +++ b/parm/config/gfs/config.ocnanal @@ -18,8 +18,6 @@ export DOMAIN_STACK_SIZE=116640000 #TODO: Make the stack size resolution depend export JEDI_BIN=${HOMEgfs}/sorc/gdas.cd/build/bin export SOCA_FIX_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/soca_fix_stage.yaml.j2" -export COMIN_OBS=@COMIN_OBS@ - # NICAS export NICAS_RESOL=@NICAS_RESOL@ export NICAS_GRID_SIZE=@NICAS_GRID_SIZE@ diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.ocnanalletkf index 6dcdcd311b..a6fca21dfe 100644 --- a/parm/config/gfs/config.ocnanalletkf +++ b/parm/config/gfs/config.ocnanalletkf @@ -8,9 +8,9 @@ echo "BEGIN: config.ocnanalletkf" # Get task specific resources . "${EXPDIR}/config.resources" ocnanalletkf -export MARINE_LETKF_EXEC="${JEDI_BIN}/gdas.x" -export MARINE_LETKF_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf.yaml.j2" -export MARINE_LETKF_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf_stage.yaml.j2" +export OCEAN_LETKF_EXEC="${JEDI_BIN}/gdas.x" +export OCEAN_LETKF_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf.yaml.j2" +export OCEAN_LETKF_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf_stage.yaml.j2" export GRIDGEN_EXEC="${JEDI_BIN}/gdas_soca_gridgen.x" export GRIDGEN_YAML="${PARMgfs}/gdas/soca/gridgen/gridgen.yaml" diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 0f1b331cbf..7163208d07 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -8,11 +8,9 @@ from typing import Dict from wxflow import (AttrDict, datetime_to_YMDH, - Executable, FileHandler, logit, parse_j2yaml, - WorkflowException, YAMLFile) logger = getLogger(__name__.split('.')[-1]) @@ -40,7 +38,7 @@ def __init__(self, config: Dict) -> None: _half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) _letkf_yaml_file = 'letkf.yaml' - _letkf_exec_args = [self.config.MARINE_LETKF_EXEC, + _letkf_exec_args = [self.config.OCEAN_LETKF_EXEC, 'fv3jedi', 'localensembleda', _letkf_yaml_file] @@ -73,7 +71,7 @@ def initialize(self): logger.info("initialize") # make directories and stage ensemble background files - letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, self.task_config) + letkf_stage_list = parse_j2yaml(self.task_config.OCEAN_LETKF_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_list).sync() letkf_stage_fix_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_fix_list).sync() @@ -106,7 +104,7 @@ def initialize(self): FileHandler({'copy': obs_files_to_copy}).sync() # make the letkf.yaml - letkf_yaml = parse_j2yaml(self.task_config.MARINE_LETKF_YAML_TMPL, self.task_config) + letkf_yaml = parse_j2yaml(self.task_config.OCEAN_LETKF_YAML_TMPL, self.task_config) letkf_yaml.observations.observers = obs_to_use letkf_yaml.save(self.task_config.letkf_yaml_file) From e82cc8bd5d118aa431aaf60ad19eb4e79fb47afe Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 21 Jun 2024 13:26:03 +0000 Subject: [PATCH 40/50] com to comin --- jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF | 6 +++--- ush/python/pygfs/task/marine_letkf.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF index d05a013382..ca274ada5c 100755 --- a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -16,10 +16,10 @@ export GDUMP=${GDUMP:-"gdas"} export GDUMP_ENS="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ - COM_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ - COM_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL + COMIN_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ + COMIN_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL -YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COM_OBS +YMD=${PDY} HH=${cyc} declare_from_tmpl -rx COMIN_OBS:COM_OBS_TMPL ############################################## # Begin JOB SPECIFIC work diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 7163208d07..c194b1ee87 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -89,16 +89,16 @@ def initialize(self): obs_files_to_copy = [] obs_to_use = [] - # copy obs from COM_OBS to DATA/obs + # copy obs from COMIN_OBS to DATA/obs for obs_file, ob in obs_files: - obs_src = path.join(self.task_config.COM_OBS, obs_file) + obs_src = path.join(self.task_config.COMIN_OBS, obs_file) obs_dst = path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) if path.exists(obs_src): logger.info(f"will try to stage {obs_file}") obs_files_to_copy.append([obs_src, obs_dst]) obs_to_use.append(ob) else: - logger.info(f"{obs_file} is not available in {self.task_config.COM_OBS}") + logger.info(f"{obs_file} is not available in {self.task_config.COMIN_OBS}") # stage the desired obs files FileHandler({'copy': obs_files_to_copy}).sync() From 3c14300ed777c9e027ec2f386d7755b3443c5c00 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Tue, 25 Jun 2024 21:39:20 +0000 Subject: [PATCH 41/50] changes to conform to latest wxflow --- ush/python/pygfs/task/marine_letkf.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index c194b1ee87..5a91da3be5 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -36,26 +36,20 @@ def __init__(self, config: Dict) -> None: logger.info("init") super().__init__(config) - _half_assim_freq = timedelta(hours=int(self.config.assim_freq) / 2) + _half_assim_freq = timedelta(hours=int(self.task_config.assim_freq) / 2) _letkf_yaml_file = 'letkf.yaml' - _letkf_exec_args = [self.config.OCEAN_LETKF_EXEC, + _letkf_exec_args = [self.task_config.OCEAN_LETKF_EXEC, 'fv3jedi', 'localensembleda', _letkf_yaml_file] - local_dict = AttrDict( - { - 'WINDOW_BEGIN': self.runtime_config.current_cycle - _half_assim_freq, - 'WINDOW_MIDDLE': self.runtime_config.current_cycle, - 'letkf_exec_args': _letkf_exec_args, - 'letkf_yaml_file': _letkf_yaml_file, - 'mom_input_nml_tmpl': path.join(self.runtime_config.DATA, 'mom_input.nml.tmpl'), - 'mom_input_nml': path.join(self.runtime_config.DATA, 'mom_input.nml'), - 'obs_dir': path.join(self.runtime_config.DATA, 'obs') - } - ) - - self.task_config = AttrDict(dict(**self.config, **self.runtime_config, **local_dict)) + self.task_config.WINDOW_MIDDLE = self.task_config.current_cycle + self.task_config.WINDOW_BEGIN = self.task_config.current_cycle - _half_assim_freq + self.task_config.letkf_exec_args = _letkf_exec_args + self.task_config.letkf_yaml_file = _letkf_yaml_file + self.task_config.mom_input_nml_tmpl = path.join(self.task_config.DATA, 'mom_input.nml.tmpl') + self.task_config.mom_input_nml = path.join(self.task_config.DATA, 'mom_input.nml') + self.task_config.obs_dir = path.join(self.task_config.DATA, 'obs') @logit(logger) def initialize(self): @@ -80,7 +74,7 @@ def initialize(self): obs_list = YAMLFile(self.task_config.OBS_YAML) # get the list of observations - CDATE = datetime_to_YMDH(self.runtime_config.current_cycle) + CDATE = datetime_to_YMDH(self. task_config.current_cycle) obs_files = [] for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() From cca206e4e3a30d44a71e3d2eca5d80ccbf6b5d84 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 26 Jun 2024 13:26:08 +0000 Subject: [PATCH 42/50] preliminary name change --- ..._OCEAN_ANALYSIS_LETKF => JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF} | 0 jobs/rocoto/ocnanalletkf.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename jobs/{JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF => JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF} (100%) diff --git a/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF b/jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF similarity index 100% rename from jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF rename to jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF diff --git a/jobs/rocoto/ocnanalletkf.sh b/jobs/rocoto/ocnanalletkf.sh index f710be5710..8d42efc135 100755 --- a/jobs/rocoto/ocnanalletkf.sh +++ b/jobs/rocoto/ocnanalletkf.sh @@ -18,6 +18,6 @@ export PYTHONPATH ############################################################### # Execute the JJOB -"${HOMEgfs}/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF" +"${HOMEgfs}/jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF" status=$? exit "${status}" From 94b9f4f4cc4bb8177dc5751a29d12a140a15957e Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 26 Jun 2024 13:40:45 +0000 Subject: [PATCH 43/50] ocean to marine --- parm/config/gfs/config.ocnanalletkf | 6 +++--- ush/python/pygfs/task/marine_letkf.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.ocnanalletkf index a6fca21dfe..6dcdcd311b 100644 --- a/parm/config/gfs/config.ocnanalletkf +++ b/parm/config/gfs/config.ocnanalletkf @@ -8,9 +8,9 @@ echo "BEGIN: config.ocnanalletkf" # Get task specific resources . "${EXPDIR}/config.resources" ocnanalletkf -export OCEAN_LETKF_EXEC="${JEDI_BIN}/gdas.x" -export OCEAN_LETKF_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf.yaml.j2" -export OCEAN_LETKF_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf_stage.yaml.j2" +export MARINE_LETKF_EXEC="${JEDI_BIN}/gdas.x" +export MARINE_LETKF_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf.yaml.j2" +export MARINE_LETKF_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf_stage.yaml.j2" export GRIDGEN_EXEC="${JEDI_BIN}/gdas_soca_gridgen.x" export GRIDGEN_YAML="${PARMgfs}/gdas/soca/gridgen/gridgen.yaml" diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 5a91da3be5..c2a8e20739 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -38,7 +38,7 @@ def __init__(self, config: Dict) -> None: _half_assim_freq = timedelta(hours=int(self.task_config.assim_freq) / 2) _letkf_yaml_file = 'letkf.yaml' - _letkf_exec_args = [self.task_config.OCEAN_LETKF_EXEC, + _letkf_exec_args = [self.task_config.MARINE_LETKF_EXEC, 'fv3jedi', 'localensembleda', _letkf_yaml_file] @@ -65,7 +65,7 @@ def initialize(self): logger.info("initialize") # make directories and stage ensemble background files - letkf_stage_list = parse_j2yaml(self.task_config.OCEAN_LETKF_STAGE_YAML_TMPL, self.task_config) + letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_list).sync() letkf_stage_fix_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_fix_list).sync() @@ -98,7 +98,7 @@ def initialize(self): FileHandler({'copy': obs_files_to_copy}).sync() # make the letkf.yaml - letkf_yaml = parse_j2yaml(self.task_config.OCEAN_LETKF_YAML_TMPL, self.task_config) + letkf_yaml = parse_j2yaml(self.task_config.MARINE_LETKF_YAML_TMPL, self.task_config) letkf_yaml.observations.observers = obs_to_use letkf_yaml.save(self.task_config.letkf_yaml_file) From d3155c9890541994dd67d87bb44b56cab4776c3f Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 26 Jun 2024 20:13:37 +0000 Subject: [PATCH 44/50] review suggestions --- ...OBAL_MARINE_ANALYSIS_LETKF => JGLOBAL_MARINE_ANALYSIS_LETKF} | 2 +- jobs/rocoto/ocnanalletkf.sh | 2 +- ush/python/pygfs/task/marine_letkf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename jobs/{JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF => JGLOBAL_MARINE_ANALYSIS_LETKF} (98%) diff --git a/jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF b/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF similarity index 98% rename from jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF rename to jobs/JGLOBAL_MARINE_ANALYSIS_LETKF index ca274ada5c..ff6116c04a 100755 --- a/jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF +++ b/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF @@ -12,7 +12,7 @@ GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") gPDY=${GDATE:0:8} gcyc=${GDATE:8:2} -export GDUMP=${GDUMP:-"gdas"} +export GDUMP="gdas" export GDUMP_ENS="enkf${GDUMP}" YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ diff --git a/jobs/rocoto/ocnanalletkf.sh b/jobs/rocoto/ocnanalletkf.sh index 8d42efc135..a9a686c396 100755 --- a/jobs/rocoto/ocnanalletkf.sh +++ b/jobs/rocoto/ocnanalletkf.sh @@ -18,6 +18,6 @@ export PYTHONPATH ############################################################### # Execute the JJOB -"${HOMEgfs}/jobs/JGDAS_GLOBAL_MARINE_ANALYSIS_LETKF" +"${HOMEgfs}/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF" status=$? exit "${status}" diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index c2a8e20739..e9887ad96c 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -39,7 +39,7 @@ def __init__(self, config: Dict) -> None: _half_assim_freq = timedelta(hours=int(self.task_config.assim_freq) / 2) _letkf_yaml_file = 'letkf.yaml' _letkf_exec_args = [self.task_config.MARINE_LETKF_EXEC, - 'fv3jedi', + 'soca', 'localensembleda', _letkf_yaml_file] From 284c4eadba5e3015dc769a42b7096b3fd72a1476 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 26 Jun 2024 20:45:20 +0000 Subject: [PATCH 45/50] timedelta -> to_timedelta --- ush/python/pygfs/task/marine_letkf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index e9887ad96c..0328df82c8 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -from datetime import timedelta import f90nml from logging import getLogger from os import path @@ -11,6 +10,7 @@ FileHandler, logit, parse_j2yaml, + to_timedelta, YAMLFile) logger = getLogger(__name__.split('.')[-1]) @@ -36,7 +36,7 @@ def __init__(self, config: Dict) -> None: logger.info("init") super().__init__(config) - _half_assim_freq = timedelta(hours=int(self.task_config.assim_freq) / 2) + _half_assim_freq = to_timedelta(f"{self.task_config.assim_freq}H") / 2 _letkf_yaml_file = 'letkf.yaml' _letkf_exec_args = [self.task_config.MARINE_LETKF_EXEC, 'soca', From db8d5bfa83ae1bbb35f851eb9ab3aeab9a7c78a0 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 26 Jun 2024 21:45:51 +0000 Subject: [PATCH 46/50] review suggestions --- ush/python/pygfs/task/marine_letkf.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 0328df82c8..412ed64192 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -2,16 +2,14 @@ import f90nml from logging import getLogger -from os import path +import os from pygfs.task.analysis import Analysis from typing import Dict -from wxflow import (AttrDict, - datetime_to_YMDH, - FileHandler, +from wxflow import (FileHandler, logit, parse_j2yaml, to_timedelta, - YAMLFile) + to_YMDH) logger = getLogger(__name__.split('.')[-1]) @@ -47,9 +45,9 @@ def __init__(self, config: Dict) -> None: self.task_config.WINDOW_BEGIN = self.task_config.current_cycle - _half_assim_freq self.task_config.letkf_exec_args = _letkf_exec_args self.task_config.letkf_yaml_file = _letkf_yaml_file - self.task_config.mom_input_nml_tmpl = path.join(self.task_config.DATA, 'mom_input.nml.tmpl') - self.task_config.mom_input_nml = path.join(self.task_config.DATA, 'mom_input.nml') - self.task_config.obs_dir = path.join(self.task_config.DATA, 'obs') + self.task_config.mom_input_nml_tmpl = os.path.join(self.task_config.DATA, 'mom_input.nml.tmpl') + self.task_config.mom_input_nml = os.path.join(self.task_config.DATA, 'mom_input.nml') + self.task_config.obs_dir = os.path.join(self.task_config.DATA, 'obs') @logit(logger) def initialize(self): @@ -70,24 +68,22 @@ def initialize(self): letkf_stage_fix_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_fix_list).sync() - # TODO(AFE): probably needs to be jinjafied - obs_list = YAMLFile(self.task_config.OBS_YAML) + obs_list = parse_j2yaml(self.task_config.OBS_YAML, self.task_config) # get the list of observations - CDATE = datetime_to_YMDH(self. task_config.current_cycle) obs_files = [] for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() - obs_filename = f"{self.task_config.RUN}.t{self.task_config.cyc}z.{obs_name}.{CDATE}.nc4" + obs_filename = f"{self.task_config.RUN}.t{self.task_config.cyc}z.{obs_name}.{to_YMDH(self.task_config.current_cycle)}.nc4" obs_files.append((obs_filename, ob)) obs_files_to_copy = [] obs_to_use = [] # copy obs from COMIN_OBS to DATA/obs for obs_file, ob in obs_files: - obs_src = path.join(self.task_config.COMIN_OBS, obs_file) - obs_dst = path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) - if path.exists(obs_src): + obs_src = os.path.join(self.task_config.COMIN_OBS, obs_file) + obs_dst = os.path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) + if os.path.exists(obs_src): logger.info(f"will try to stage {obs_file}") obs_files_to_copy.append([obs_src, obs_dst]) obs_to_use.append(ob) From 046f42258a5d6b5298a374f31f071fbed930d37a Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Wed, 26 Jun 2024 21:48:38 +0000 Subject: [PATCH 47/50] style points --- ush/python/pygfs/task/marine_letkf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 412ed64192..4127006f13 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -45,9 +45,9 @@ def __init__(self, config: Dict) -> None: self.task_config.WINDOW_BEGIN = self.task_config.current_cycle - _half_assim_freq self.task_config.letkf_exec_args = _letkf_exec_args self.task_config.letkf_yaml_file = _letkf_yaml_file - self.task_config.mom_input_nml_tmpl = os.path.join(self.task_config.DATA, 'mom_input.nml.tmpl') - self.task_config.mom_input_nml = os.path.join(self.task_config.DATA, 'mom_input.nml') - self.task_config.obs_dir = os.path.join(self.task_config.DATA, 'obs') + self.task_config.mom_input_nml_tmpl = os.path.join(self.task_config.DATA, 'mom_input.nml.tmpl') + self.task_config.mom_input_nml = os.path.join(self.task_config.DATA, 'mom_input.nml') + self.task_config.obs_dir = os.path.join(self.task_config.DATA, 'obs') @logit(logger) def initialize(self): @@ -81,8 +81,8 @@ def initialize(self): obs_to_use = [] # copy obs from COMIN_OBS to DATA/obs for obs_file, ob in obs_files: - obs_src = os.path.join(self.task_config.COMIN_OBS, obs_file) - obs_dst = os.path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) + obs_src = os.path.join(self.task_config.COMIN_OBS, obs_file) + obs_dst = os.path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) if os.path.exists(obs_src): logger.info(f"will try to stage {obs_file}") obs_files_to_copy.append([obs_src, obs_dst]) From 96969f854b4d7e649ee1f3ec503d2a6257c4cc59 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 27 Jun 2024 15:32:26 +0000 Subject: [PATCH 48/50] review suggestions --- ush/python/pygfs/task/marine_letkf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 4127006f13..fe5de9f3f5 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -74,7 +74,7 @@ def initialize(self): obs_files = [] for ob in obs_list['observers']: obs_name = ob['obs space']['name'].lower() - obs_filename = f"{self.task_config.RUN}.t{self.task_config.cyc}z.{obs_name}.{to_YMDH(self.task_config.current_cycle)}.nc4" + obs_filename = f"{self.task_config.RUN}.t{self.task_config.cyc}z.{obs_name}.{to_YMDH(self.task_config.current_cycle)}.nc" obs_files.append((obs_filename, ob)) obs_files_to_copy = [] @@ -84,11 +84,10 @@ def initialize(self): obs_src = os.path.join(self.task_config.COMIN_OBS, obs_file) obs_dst = os.path.join(self.task_config.DATA, self.task_config.obs_dir, obs_file) if os.path.exists(obs_src): - logger.info(f"will try to stage {obs_file}") obs_files_to_copy.append([obs_src, obs_dst]) obs_to_use.append(ob) else: - logger.info(f"{obs_file} is not available in {self.task_config.COMIN_OBS}") + logger.warning(f"{obs_file} is not available in {self.task_config.COMIN_OBS}") # stage the desired obs files FileHandler({'copy': obs_files_to_copy}).sync() From 6056395e961dff61173c6d73dee349025f0c748c Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Thu, 27 Jun 2024 18:34:24 +0000 Subject: [PATCH 49/50] remove GDUMP --- jobs/JGLOBAL_MARINE_ANALYSIS_LETKF | 3 --- ush/python/pygfs/task/marine_letkf.py | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF b/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF index ff6116c04a..3b3f0a7eff 100755 --- a/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF +++ b/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF @@ -12,9 +12,6 @@ GDATE=$(date --utc +%Y%m%d%H -d "${PDY} ${cyc} - ${assim_freq} hours") gPDY=${GDATE:0:8} gcyc=${GDATE:8:2} -export GDUMP="gdas" -export GDUMP_ENS="enkf${GDUMP}" - YMD=${gPDY} HH=${gcyc} declare_from_tmpl -rx \ COMIN_OCEAN_HISTORY_PREV:COM_OCEAN_HISTORY_TMPL \ COMIN_ICE_HISTORY_PREV:COM_ICE_HISTORY_TMPL diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index fe5de9f3f5..d9dad56e98 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -5,7 +5,8 @@ import os from pygfs.task.analysis import Analysis from typing import Dict -from wxflow import (FileHandler, +from wxflow import (AttrDict, + FileHandler, logit, parse_j2yaml, to_timedelta, @@ -63,7 +64,13 @@ def initialize(self): logger.info("initialize") # make directories and stage ensemble background files - letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, self.task_config) + ensbkgconf = AttrDict() + keys = ['previous_cycle', 'current_cycle', 'DATA', 'NMEM_ENS', + 'PARMgfs', 'ROTDIR', 'COM_OCEAN_HISTORY_TMPL', 'COM_ICE_HISTORY_TMPL'] + for key in keys: + ensbkgconf[key] = self.task_config[key] + ensbkgconf.RUN = 'enkfgdas' + letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, ensbkgconf) FileHandler(letkf_stage_list).sync() letkf_stage_fix_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_fix_list).sync() @@ -93,7 +100,12 @@ def initialize(self): FileHandler({'copy': obs_files_to_copy}).sync() # make the letkf.yaml - letkf_yaml = parse_j2yaml(self.task_config.MARINE_LETKF_YAML_TMPL, self.task_config) + letkfconf = AttrDict() + keys = ['WINDOW_BEGIN', 'WINDOW_MIDDLE', 'RUN', 'gcyc', 'NMEM_ENS'] + for key in keys: + letkfconf[key] = self.task_config[key] + letkfconf.RUN = 'enkfgdas' + letkf_yaml = parse_j2yaml(self.task_config.MARINE_LETKF_YAML_TMPL, letkfconf) letkf_yaml.observations.observers = obs_to_use letkf_yaml.save(self.task_config.letkf_yaml_file) From 2a4dd7009e2fcf8885ac39d45bd8a7e871c82298 Mon Sep 17 00:00:00 2001 From: AndrewEichmann-NOAA Date: Fri, 5 Jul 2024 18:24:16 +0000 Subject: [PATCH 50/50] ocnanalletkf to marineanalletkf and moving setup yamls --- env/HERA.env | 10 +++++----- env/ORION.env | 10 +++++----- jobs/JGLOBAL_MARINE_ANALYSIS_LETKF | 2 +- .../{ocnanalletkf.sh => marineanalletkf.sh} | 2 +- ...ig.ocnanalletkf => config.marineanalletkf} | 8 ++++---- parm/config/gfs/config.ocnanal | 3 ++- parm/config/gfs/config.resources | 20 +++++++++---------- ush/python/pygfs/task/marine_letkf.py | 8 +++++--- 8 files changed, 33 insertions(+), 30 deletions(-) rename jobs/rocoto/{ocnanalletkf.sh => marineanalletkf.sh} (95%) rename parm/config/gfs/{config.ocnanalletkf => config.marineanalletkf} (70%) diff --git a/env/HERA.env b/env/HERA.env index db63f0bfa5..b743a19a62 100755 --- a/env/HERA.env +++ b/env/HERA.env @@ -140,13 +140,13 @@ elif [[ "${step}" = "ocnanalecen" ]]; then [[ ${NTHREADS_OCNANALECEN} -gt ${nth_max} ]] && export NTHREADS_OCNANALECEN=${nth_max} export APRUN_OCNANALECEN="${launcher} -n ${npe_ocnanalecen} --cpus-per-task=${NTHREADS_OCNANALECEN}" -elif [[ "${step}" = "ocnanalletkf" ]]; then +elif [[ "${step}" = "marineanalletkf" ]]; then - nth_max=$((npe_node_max / npe_node_ocnanalletkf)) + nth_max=$((npe_node_max / npe_node_marineanalletkf)) - export NTHREADS_OCNANALLETKF=${nth_ocnanalletkf:-${nth_max}} - [[ ${NTHREADS_OCNANALLETKF} -gt ${nth_max} ]] && export NTHREADS_OCNANALLETKF=${nth_max} - export APRUN_OCNANALLETKF="${launcher} -n ${npe_ocnanalletkf} --cpus-per-task=${NTHREADS_OCNANALLETKF}" + export NTHREADS_MARINEANALLETKF=${nth_marineanalletkf:-${nth_max}} + [[ ${NTHREADS_MARINEANALLETKF} -gt ${nth_max} ]] && export NTHREADS_MARINEANALLETKF=${nth_max} + export APRUN_MARINEANALLETKF="${launcher} -n ${npe_marineanalletkf} --cpus-per-task=${NTHREADS_MARINEANALLETKF}" elif [[ "${step}" = "anal" ]] || [[ "${step}" = "analcalc" ]]; then diff --git a/env/ORION.env b/env/ORION.env index 502e99e192..c203acae48 100755 --- a/env/ORION.env +++ b/env/ORION.env @@ -148,13 +148,13 @@ elif [[ "${step}" = "ocnanalecen" ]]; then [[ ${NTHREADS_OCNANALECEN} -gt ${nth_max} ]] && export NTHREADS_OCNANALECEN=${nth_max} export APRUN_OCNANALECEN="${launcher} -n ${npe_ocnanalecen} --cpus-per-task=${NTHREADS_OCNANALECEN}" -elif [[ "${step}" = "ocnanalletkf" ]]; then +elif [[ "${step}" = "marineanalletkf" ]]; then - nth_max=$((npe_node_max / npe_node_ocnanalletkf)) + nth_max=$((npe_node_max / npe_node_marineanalletkf)) - export NTHREADS_OCNANALLETKF=${nth_ocnanalletkf:-${nth_max}} - [[ ${NTHREADS_OCNANALLETKF} -gt ${nth_max} ]] && export NTHREADS_OCNANALLETKF=${nth_max} - export APRUN_OCNANALLETKF="${launcher} -n ${npe_ocnanalletkf} --cpus-per-task=${NTHREADS_OCNANALLETKF}" + export NTHREADS_MARINEANALLETKF=${nth_marineanalletkf:-${nth_max}} + [[ ${NTHREADS_MARINEANALLETKF} -gt ${nth_max} ]] && export NTHREADS_MARINEANALLETKF=${nth_max} + export APRUN_MARINEANALLETKF="${launcher} -n ${npe_marineanalletkf} --cpus-per-task=${NTHREADS_MARINEANALLETKF}" elif [[ "${step}" = "anal" ]] || [[ "${step}" = "analcalc" ]]; then diff --git a/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF b/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF index 3b3f0a7eff..38dc3049f9 100755 --- a/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF +++ b/jobs/JGLOBAL_MARINE_ANALYSIS_LETKF @@ -1,6 +1,6 @@ #!/bin/bash source "${HOMEgfs}/ush/preamble.sh" -source "${HOMEgfs}/ush/jjob_header.sh" -e "ocnanalletkf" -c "base ocnanal ocnanalletkf" +source "${HOMEgfs}/ush/jjob_header.sh" -e "marineanalletkf" -c "base ocnanal marineanalletkf" ############################################## # Set variables used in the script diff --git a/jobs/rocoto/ocnanalletkf.sh b/jobs/rocoto/marineanalletkf.sh similarity index 95% rename from jobs/rocoto/ocnanalletkf.sh rename to jobs/rocoto/marineanalletkf.sh index a9a686c396..f2bfb9f70c 100755 --- a/jobs/rocoto/ocnanalletkf.sh +++ b/jobs/rocoto/marineanalletkf.sh @@ -8,7 +8,7 @@ source "${HOMEgfs}/ush/preamble.sh" status=$? [[ ${status} -ne 0 ]] && exit "${status}" -export job="ocnanalletkf" +export job="marineanalletkf" export jobid="${job}.$$" ############################################################### diff --git a/parm/config/gfs/config.ocnanalletkf b/parm/config/gfs/config.marineanalletkf similarity index 70% rename from parm/config/gfs/config.ocnanalletkf rename to parm/config/gfs/config.marineanalletkf index 6dcdcd311b..fde3433a13 100644 --- a/parm/config/gfs/config.ocnanalletkf +++ b/parm/config/gfs/config.marineanalletkf @@ -1,12 +1,12 @@ #!/bin/bash -########## config.ocnanalletkf ########## +########## config.marineanalletkf ########## # Ocn Analysis specific -echo "BEGIN: config.ocnanalletkf" +echo "BEGIN: config.marineanalletkf" # Get task specific resources -. "${EXPDIR}/config.resources" ocnanalletkf +. "${EXPDIR}/config.resources" marineanalletkf export MARINE_LETKF_EXEC="${JEDI_BIN}/gdas.x" export MARINE_LETKF_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf.yaml.j2" @@ -15,4 +15,4 @@ export MARINE_LETKF_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/letkf_stage.yaml export GRIDGEN_EXEC="${JEDI_BIN}/gdas_soca_gridgen.x" export GRIDGEN_YAML="${PARMgfs}/gdas/soca/gridgen/gridgen.yaml" -echo "END: config.ocnanalletkf" +echo "END: config.marineanalletkf" diff --git a/parm/config/gfs/config.ocnanal b/parm/config/gfs/config.ocnanal index 14d24fccbd..367e570ec8 100644 --- a/parm/config/gfs/config.ocnanal +++ b/parm/config/gfs/config.ocnanal @@ -16,7 +16,8 @@ export SOCA_NINNER=@SOCA_NINNER@ export CASE_ANL=@CASE_ANL@ export DOMAIN_STACK_SIZE=116640000 #TODO: Make the stack size resolution dependent export JEDI_BIN=${HOMEgfs}/sorc/gdas.cd/build/bin -export SOCA_FIX_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/letkf/soca_fix_stage.yaml.j2" +export SOCA_FIX_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/soca_fix_stage.yaml.j2" +export SOCA_ENS_BKG_STAGE_YAML_TMPL="${PARMgfs}/gdas/soca/soca_ens_bkg_stage.yaml.j2" # NICAS export NICAS_RESOL=@NICAS_RESOL@ diff --git a/parm/config/gfs/config.resources b/parm/config/gfs/config.resources index 5c3a100880..e16524ecd3 100644 --- a/parm/config/gfs/config.resources +++ b/parm/config/gfs/config.resources @@ -25,7 +25,7 @@ if (( $# != 1 )); then echo "waveinit waveprep wavepostsbs wavepostbndpnt wavepostbndpntbll wavepostpnt" echo "wavegempak waveawipsbulls waveawipsgridded" echo "postsnd awips gempak npoess" - echo "ocnanalprep prepoceanobs ocnanalbmat ocnanalrun ocnanalecen ocnanalletkf ocnanalchkpt ocnanalpost ocnanalvrfy" + echo "ocnanalprep prepoceanobs ocnanalbmat ocnanalrun ocnanalecen marineanalletkf ocnanalchkpt ocnanalpost ocnanalvrfy" exit 1 fi @@ -557,32 +557,32 @@ case ${step} in export memory_ocnanalecen ;; - "ocnanalletkf") + "marineanalletkf") npes=16 case ${OCNRES} in "025") npes=480 - memory_ocnanalletkf="96GB" + memory_marineanalletkf="96GB" ;; "050") npes=16 - memory_ocnanalletkf="96GB" + memory_marineanalletkf="96GB" ;; "500") npes=16 - memory_ocnanalletkf="24GB" + memory_marineanalletkf="24GB" ;; *) echo "FATAL ERROR: Resources not defined for job ${step} at resolution ${OCNRES}" exit 4 esac - export wtime_ocnanalletkf="00:10:00" - export npe_ocnanalletkf=${npes} - export nth_ocnanalletkf=1 + export wtime_marineanalletkf="00:10:00" + export npe_marineanalletkf=${npes} + export nth_marineanalletkf=1 export is_exclusive=True - export npe_node_ocnanalletkf=$(( npe_node_max / nth_ocnanalletkf )) - export memory_ocnanalletkf + export npe_node_marineanalletkf=$(( npe_node_max / nth_marineanalletkf )) + export memory_marineanalletkf ;; diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index d9dad56e98..0fdd3d9aba 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -70,10 +70,12 @@ def initialize(self): for key in keys: ensbkgconf[key] = self.task_config[key] ensbkgconf.RUN = 'enkfgdas' - letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, ensbkgconf) + soca_ens_bkg_stage_list = parse_j2yaml(self.task_config.SOCA_ENS_BKG_STAGE_YAML_TMPL, ensbkgconf) + FileHandler(soca_ens_bkg_stage_list).sync() + soca_fix_stage_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) + FileHandler(soca_fix_stage_list).sync() + letkf_stage_list = parse_j2yaml(self.task_config.MARINE_LETKF_STAGE_YAML_TMPL, self.task_config) FileHandler(letkf_stage_list).sync() - letkf_stage_fix_list = parse_j2yaml(self.task_config.SOCA_FIX_STAGE_YAML_TMPL, self.task_config) - FileHandler(letkf_stage_fix_list).sync() obs_list = parse_j2yaml(self.task_config.OBS_YAML, self.task_config)