diff --git a/env/HERA.env b/env/HERA.env index 68dbd4d396..fbfdb68e92 100755 --- a/env/HERA.env +++ b/env/HERA.env @@ -130,6 +130,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 795346f0c6..1b66ca65c0 100755 --- a/env/ORION.env +++ b/env/ORION.env @@ -138,6 +138,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..d03ddfc19a --- /dev/null +++ b/jobs/JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF @@ -0,0 +1,48 @@ +#!/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") + +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 + +############################################## +# Begin JOB SPECIFIC work +############################################## + +############################################################### +# Run relevant script + +EXSCRIPT=${GDASOCNLETKFPY:-${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..f710be5710 --- /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}/ush/python" +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 e2893d6337..d58ecf85b2 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 @@ -456,6 +456,35 @@ case ${step} in export memory_ocnanalecen ;; + "ocnanalletkf") + npes=16 + case ${OCNRES} in + "025") + npes=480 + 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/scripts/exgdas_global_marine_analysis_letkf.py b/scripts/exgdas_global_marine_analysis_letkf.py new file mode 100755 index 0000000000..37ca837889 --- /dev/null +++ b/scripts/exgdas_global_marine_analysis_letkf.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# exgdas_global_marine_analysis_letkf.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 +from pygfs.task.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 marine letkf task + MarineLetkf = MarineLETKF(config) + MarineLetkf.initialize() + MarineLetkf.run() + MarineLetkf.finalize() diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py new file mode 100644 index 0000000000..0ae5bea98d --- /dev/null +++ b/ush/python/pygfs/task/marine_letkf.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +from logging import getLogger +from pygfs.task.analysis import Analysis +from typing import Dict +from wxflow import (chdir, + logit, + Task) + +logger = getLogger(__name__.split('.')[-1]) + + +class MarineLETKF(Analysis): + """ + Class for global ocean and sea ice analysis LETKF task + """ + + @logit(logger, name="MarineLETKF") + def __init__(self, config: Dict) -> None: + """Constructor for ocean and sea ice 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 and sea ice LETKF task + Parameters: + ------------ + None + Returns: + -------- + None + """ + + logger.info("initialize") + + @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) + + @logit(logger) + def finalize(self): + """Method finalize for ocean and sea ice LETKF task + Parameters: + ------------ + None + Returns: + -------- + None + """ + + logger.info("finalize")